创建去中心化的分布式 Puppet 架构

I have the world’s largest collection of seashells. I keep it scattered around the beaches of the world… perhaps you’ve seen it.

— Steven Wright

某些系统(尤其像 Mafia)在去中心化的分布式架构环境下运行良好。 使用 Puppet 的一个最常见的方法是运行一个 Puppetmaster 服务器, Puppet 客户端连接这个服务器并从它获取配置清单。 无论如何,你仍旧可以使用下面的方法直接针对配置清单运行 puppet apply 命令。 (通常会使用 -v 参数开启冗余输出模式, 这样就可以看到详细的执行过程):

# puppet apply -v manifest.pp
info: Applying configuration version '1294313350'

你甚至可以直接在命令行上运行配置清单的代码片断:

# puppet apply -e "file { '/tmp/test': ensure => present }"
notice: /Stage[main]//File[/tmp/test]/ensure: created

换言之,如果能安排合适的配置清单并分发到客户端,你就可以在 Puppet 客户端上直接执行它,而不必使用中心化的 Puppetmaster 服务器。 这将消除单台 Puppetmaster 服务器的性能瓶颈,也消除了单点故障。 与此同时,也避免了新增客户端时 SSL 证书签署以及证书交换的步骤。

将配置清单文件推送到客户端有多种实现方法, 显然 Git (或者其它版本控制系统,如 Mercurial 或 Subversion)能为你做绝大部分的工作。 你可以在本地编辑 Puppet 配置清单的本地副本,提交到 Git 并将更新推送到中心仓库, 然后从 Git 中心仓库自动将配置清单分发到客户机。

准备工作

如果你的 Puppet 配置清单还没有纳入 Git,请参考本章 使用版本控制 一节的操作步骤。

操作步骤

  1. 在客户端使用如下命令对 Puppet 仓库克隆一个裸仓库(裸仓库没有工作区,只包含 .git 目录中的所有内容):

    # git clone --bare ssh://[email protected]/var/git/puppet
    
  2. 使用如下命令检出裸仓库内容到 /etc/puppet/ 目录:

    # git archive --format=tar HEAD | (cd /etc/puppet && tar xf -)
    
  3. 使用 Puppet 命令执行 site.pp 文件

    # puppet apply -v /etc/puppet/manifests/site.pp
    info: Applying configuration version '1294313353'
    

    一旦完成上面的工作,下一步就是配置仓库的自动推送将变动推送到客户端。 使用 Git 的 remote 命令可以实现此功能,即配置本地仓库的远程仓库别名。例如:

    # git remote add web ssh://[email protected]/etc/puppet
    

    如果你有多个客户端, 可以为同一个远程别名添加多个 URL:

    # git remote set-url --add webs ssh://[email protected]/etc/puppet
    # git remote set-url --add webs ssh://[email protected]/etc/puppet
    ...
    

    或者像这样,简单编辑 Git 配置文件 (.git/config) :

    [remote "web"]
        url = ssh://[email protected]/etc/puppet
        url = ssh://[email protected]/etc/puppet
        url = ssh://[email protected]/etc/puppet
        ...
    
  4. 现在你可以使用如下命令从 Git 中心仓库推送更新到任意一台(或一组)客户端:

    # git push web
    
  5. 最后一步,每当客户端接收到从 Git 中心仓库的推送就应该更新它自己的 /etc/puppet 目录。你可以使用 Git 的 postreceive 钩子来实现此功能。 在你的仓库中,创建一个名为 hooks/post-receive 的文件并为其设置可执行权限(0755), 文件内容为:

    #!/bin/sh
    git archive --format=tar HEAD | (cd /etc/puppet && tar xf -)
    

工作原理

与连接 Puppetmaster 获取已经编译好的客户端配置清单不同, 使用这种方式每个客户端都要从本地副本编译自己的配置清单。 每当 Git 中心服务器推送一次更新(或者从 Git 仓库 checkout 检出)就会重新编译一次。 这大大高了网络带宽的利用率,因为客户端不必每次运行时都连接 Puppetmaster。 同时也消除了单点故障,因为客户端可以从任何分布式的 Git 仓库 (这些仓库的内容是由 Git 中心仓库自动推送的)获得更新。

使用基于 Git 的去中心化的分布式 Puppet 架构为你提供了一个非常灵活的处理方式。 你可以使用 SSH 密钥来配置访问控制,按需要允许每一个客户端或一组客户端的访问。 例如:用于数据库服务器的配置清单仅允许数据库组的机器访问获取。

当然还需要一些额外的配置工作,但对于大多数小型组织是没有必要的, 这种去中心化的 Puppet 部署方式提供了额外的灵活性,同时也适用于更为苛刻的权限控制环境。

更多用法

如果你希望每次中心仓库推送更新之后 Puppet 立即执行并应用更新, 可以编辑 post-receive 脚本来完成,或者执行你需要的其它的动作。 另外,你也可以手动运行 Puppet,还可以用 从 cron 运行 Puppet 一节描述的方法使用 cron 调度运行,但要记得是运行 puppet apply , 而不是运行 puppet agent 。

使用基于 Git 的架构也存在一些缺点:不能使用 Puppet 提供的高级特性, 例如外部节点分类器(external node classifier)以及存储配置(stored configuration)等。 不管怎样,当你需要将 Puppet 的部署扩展到大量节点时,这是一种最简单的实现方式。

你可以在 Stephen Nelson-Smith 的这篇文章里找到更多更详细的关于这种架构的讨论,文章地址是: http://bitfieldconsulting.com/scaling-puppet-with-distributedversion-control

参见本书