Puppet:声明式配置管理工具

FreeGuideOnline 最新 2026-07-03

puppet package { 'nginx': ensure => installed, }

service { 'nginx': ensure => running, enable => true, require => Package['nginx'], }

上面的代码声明了一个 `nginx` 包必须被安装,并且 `nginx` 服务必须处于运行状态且开机自启,同时服务资源依赖于包资源。

### 清单(Manifest)
清单是包含 Puppet 代码的文件,扩展名为 `.pp`。清单文件中可以放置类定义、资源声明、变量、条件判断等。一个典型的项目入口清单文件是 `site.pp`,它通常用于定义节点配置。

### 类(Class)与定义(Definition)
类是一组相关资源的集合,可以重复使用。定义则是一种可以接受参数并创建多个命名实例的代码块。例如:
```puppet
class nginx {
  package { 'nginx': ensure => installed }
  service { 'nginx':
    ensure => running,
    enable => true,
    require => Package['nginx'],
  }
}

define vhost ($docroot) {
  file { "/etc/nginx/sites-available/${title}":
    content => template('nginx/vhost.conf.erb'),
  }
}

模块(Module)

模块是 Puppet 代码的组织单元,通常包含类、定义、文件模板、相关数据等。每个模块有固定的目录结构,例如:

nginx/
├── manifests/
│   └── init.pp
├── templates/
│   └── vhost.conf.erb
├── files/
└── metadata.json

Puppet 社区提供了大量预置模块(通过 Puppet Forge),可以直接安装使用。

节点分类(Node Classification)

节点的定义告诉 Puppet Master 应该把哪些配置(类、参数)分配给哪台机器。可以在 site.pp 中使用 node 块来定义:

node 'web01.example.com' {
  include nginx
  class { 'ntp': servers => ['pool.ntp.org'] }
}

更灵活的方式是通过外部节点分类器(ENC)或 Hiera 进行动态分配。

环境搭建:安装 Puppet

在生产环境中,需要至少两台机器:一台 Puppet Master 和一台或多台 Agent 节点。下面以 CentOS 7 / Rocky Linux 为例,演示快速安装过程。

安装 Puppet Master(服务器端)

  1. 添加 Puppet 官方仓库

    rpm -Uvh https://yum.puppet.com/puppet7-release-el-7.noarch.rpm
    
  2. 安装 Puppet Server 软件包

    yum install -y puppetserver
    
  3. 调整内存(可选):编辑 /etc/sysconfig/puppetserver,修改 JVM 堆内存大小以适应你的服务器。

  4. 启动并设置开机自启

    systemctl start puppetserver
    systemctl enable puppetserver
    
  5. 防火墙配置(如果开启):

    firewall-cmd --add-port=8140/tcp --permanent
    firewall-cmd --reload
    

安装 Puppet Agent(客户端)

在每台受管节点上执行:

  1. 添加仓库并安装 Puppet Agent

    rpm -Uvh https://yum.puppet.com/puppet7-release-el-7.noarch.rpm
    yum install -y puppet-agent
    
  2. 配置 Master 地址:编辑 /etc/puppetlabs/puppet/puppet.conf,在 [main][agent] 段添加:

    [agent]
    server = puppet-master.example.com
    
  3. 启动 Agent 服务并启用

    /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
    

证书签名

Agent 第一次连接 Master 时会发起证书签名请求,需要在 Master 上审核:

  • 查看待签名证书:
    /opt/puppetlabs/bin/puppetserver ca list
    
  • 签名所有请求:
    /opt/puppetlabs/bin/puppetserver ca sign --all
    

签名完成后,Agent 即可定期从 Master 获取并执行配置。

我的第一个 Puppet 清单

在 Master 上创建最简单的清单,让 Agent 安装并启动 NTP 服务。

  1. 创建模块目录(可以在主配置环境路径下):

    mkdir -p /etc/puppetlabs/code/environments/production/modules/ntp_module/manifests
    
  2. 编写类文件 init.pp

    # /etc/puppetlabs/code/environments/production/modules/ntp_module/manifests/init.pp
    class ntp_module {
      package { 'ntp':
        ensure => installed,
      }
      service { 'ntpd':
        ensure => running,
        enable => true,
        require => Package['ntp'],
      }
    }
    
  3. site.pp 中添加节点定义

    # /etc/puppetlabs/code/environments/production/manifests/site.pp
    node default {
      include ntp_module
    }
    

    这里的 default 会匹配所有未明确定义的节点。

  4. 在 Agent 上手动触发运行(测试):

    /opt/puppetlabs/bin/puppet agent --test
    

    如果一切正常,你会在输出中看到 NTP 软件包安装和服务启动的过程。此后 Agent 将按默认间隔(30分钟)自动运行。

使用模块与 Puppet Forge

Puppet Forge 是官方模块仓库,包含数千个预置模块。使用社区模块可以大幅减少编写代码的工作量。

安装模块

在 Master 上使用 puppet module install 命令:

/opt/puppetlabs/bin/puppet module install puppetlabs-ntp

该命令会将模块安装到 /etc/puppetlabs/code/environments/production/modules 下。之后可以在清单中直接使用:

include ntp

大多数模块支持参数传递,便于自定义:

class { 'ntp':
  servers => [ '0.pool.ntp.org', '1.pool.ntp.org' ],
}

管理模块依赖

模块目录中的 Puppetfile 可以描述所有依赖,并借助工具(如 r10k、Code Manager)实现自动化部署。一个简单的 Puppetfile 示例:

forge 'https://forge.puppet.com'

mod 'puppetlabs/ntp', '9.0.0'
mod 'puppetlabs/firewall', '2.8.0'

数据分离:Hiera

随着环境规模增长,直接在清单中硬编码配置值会变得难以维护。Puppet 通过 Hiera 将配置数据与代码分离。

Hiera 使用层次化的 YAML 文件存储键值对,根据节点特定的事实(如操作系统、数据中心位置、角色等)返回对应的值。例如:

hiera.yaml 层次结构

---
version: 5
defaults:
  datadir: data
  data_hash: yaml_data
hierarchy:
  - name: "Per-node data"
    path: "nodes/%{trusted.certname}.yaml"
  - name: "Common data"
    path: "common.yaml"

数据文件示例data/common.yaml

ntp::servers:
  - 0.pool.ntp.org
  - 1.pool.ntp.org

在类中使用 Hiera 数据自动查找参数: 如果 ntp 类的参数名与 Hiera 键一致,Puppet 会自动注入值。否则可以通过 lookup() 函数显式获取:

$servers = lookup('ntp::servers')

Facter:系统信息收集

Puppet 内建了 Facter 工具,它会提取目标节点的系统信息(如 IP 地址、操作系统版本、内核等),并转变为变量供 Puppet 代码使用。这些信息被称为“事实(facts)”。你可以在清单或模板中直接使用,例如:

if $facts['os']['family'] == 'RedHat' {
  $package_name = 'httpd'
} elsif $facts['os']['family'] == 'Debian' {
  $package_name = 'apache2'
}

你也可以编写自定义事实(custom facts)来提取业务相关的节点属性,放置于模块的 facts.d 目录下。

节点管理最佳实践

使用 Roles 和 Profiles 模式

当基础设施变得复杂时,建议采用 Roles & Profiles 设计:

  • Profile:一个小的功能组合,例如 “Web 服务器基础配置”、“MySQL 客户端”。
  • Role:由多个 Profile 组成,定义一个完整的节点角色,例如 “Web 应用服务器”。

这样每个节点只需分配一个 Role 类,清晰的层级便于维护。

class profile::base {
  include ntp
  include ssh
}

class role::web_server {
  include profile::base
  include profile::apache
}

版本控制与 CI/CD

所有 Puppet 代码(清单、模块、Hiera 数据)都应纳入版本控制系统(如 Git)。通过集成 Puppet Code Manager(配合 Git 分支),可以实现环境的自动部署。每次代码提交后,自动运行 Puppet 语法检查与单元测试,然后推送到 Master。

环境隔离

利用 Puppet 的目录环境(Directory Environments),可以为开发、测试、生产创建独立的代码路径,避免未测试的变更影响生产节点。

故障排查与常用命令

  • 在 Agent 上测试运行并查看详细输出:
    /opt/puppetlabs/bin/puppet agent --test --verbose
    
  • 查看 Master 端详细日志:
    tail -f /var/log/puppetlabs/puppetserver/puppetserver.log
    
  • 检查证书状态:
    /opt/puppetlabs/bin/puppetserver ca list --all
    
  • 验证清单语法:
    /opt/puppetlabs/bin/puppet parser validate <manifest.pp>
    
  • 在 Master 上模拟节点目录编译:
    /opt/puppetlabs/bin/puppet master --compile <nodename>