今天就来分享一下我这几个月使用Puppet管理多服务器配置的实战经验,包括一些踩过的坑和解决方案。
Puppet基础概念快速入门
在开始实战之前,先简单说说Puppet的核心概念,这些理解了后面的操作就很容易了。
Puppet采用的是Master-Agent架构,Master节点存储配置清单(manifest),Agent节点定期向Master请求配置并应用。整个过程是声明式的,你只需要描述想要的最终状态,Puppet会自动计算如何达到这个状态。
几个重要概念:
Manifest:用Puppet DSL语言编写的配置文件,描述系统应该是什么样子
Module:可复用的配置单元,包含manifest、文件、模板等
Node:被管理的服务器节点
Catalog:Master为每个节点编译生成的具体配置指令
环境搭建实战
我的测试环境是3台CentOS 7服务器,1台Master,2台Agent。生产环境类似,只是Agent数量更多。
Master节点安装配置
# 安装Puppet Server rpm -Uvh https://yum.puppet.com/puppet-release-el-7.noarch.rpm yum install -y puppetserver # 修改内存配置,默认2G太大了 vim /etc/sysconfig/puppetserver JAVA_ARGS="-Xms512m -Xmx512m" # 启动服务 systemctl enable puppetserver systemctl start puppetserver这里有个坑,Puppet Server默认内存配置是2G,小环境根本用不了这么多,而且会导致启动失败。我把它调到512M,测试环境够用了。
Agent节点配置
# 安装Puppet Agent rpm -Uvh https://yum.puppet.com/puppet-release-el-7.noarch.rpm yum install -y puppet-agent # 配置Master地址 vim /etc/puppetlabs/puppet/puppet.conf [main] server = puppet-master.example.com # 启动服务 systemctl enable puppet systemctl start puppetAgent第一次连接Master时需要证书认证,在Master上执行:
/opt/puppetlabs/bin/puppetserver ca list /opt/puppetlabs/bin/puppetserver ca sign --all编写第一个配置管理模块
我们从一个简单的nginx模块开始。在生产环境中,nginx的配置管理是个头疼的问题,不同环境的配置文件经常不一致。
创建nginx模块结构
cd /etc/puppetlabs/code/environments/production/modules mkdir -p nginx/{manifests,files,templates,tests}编写主配置文件
# nginx/manifests/init.pp class nginx { package { 'nginx': ensure => installed, } service { 'nginx': ensure => running, enable => true, require => Package['nginx'], } file { '/etc/nginx/nginx.conf': ensure => present, source => 'puppet:///modules/nginx/nginx.conf', owner => 'root', group => 'root', mode => '0644', notify => Service['nginx'], require => Package['nginx'], } }这个配置很简单,确保nginx包安装、服务运行、配置文件正确。notify参数很重要,当配置文件变化时会自动重启服务。
准备配置文件模板
# 将标准的nginx配置放到files目录 cp /etc/nginx/nginx.conf nginx/files/应用到节点
# site.pp node 'web-server-01.example.com' { include nginx } node 'web-server-02.example.com' { include nginx }这样两台web服务器就会自动安装和配置nginx了。每次Agent运行时(默认30分钟),都会检查配置是否符合要求,不符合就自动修复。
高级配置管理技巧
使用变量和条件判断
实际环境中,不同服务器的配置往往有差异。比如内存大小不同,nginx worker进程数就应该不同:
class nginx { $worker_processes = $facts['processors']['count'] package { 'nginx': ensure => installed, } file { '/etc/nginx/nginx.conf': ensure => present, content => template('nginx/nginx.conf.erb'), owner => 'root', group => 'root', mode => '0644', notify => Service['nginx'], require => Package['nginx'], } service { 'nginx': ensure => running, enable => true, require => [Package['nginx'], File['/etc/nginx/nginx.conf']], } }对应的ERB模板文件:
# nginx/templates/nginx.conf.erb worker_processes <%= @worker_processes %>; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; <% if @facts['memorysize_mb'].to_i > 4096 %> # 大内存服务器使用更多连接 worker_connections 2048; <% end %> }参数化模块
为了让模块更灵活,可以使用参数:
class nginx ( String $version = 'installed', Integer $worker_processes = $facts['processors']['count'], Boolean $enable_ssl = false, ) { package { 'nginx': ensure => $version, } if $enable_ssl { package { 'nginx-mod-ssl': ensure => installed, } } # 其他配置... }在site.pp中这样使用:
node 'web-server-01.example.com' { class { 'nginx': worker_processes => 8, enable_ssl => true, } }使用Hiera进行数据分离
Hiera是Puppet的数据查找系统,可以把配置数据从代码中分离出来。这在管理多环境时特别有用。
# /etc/puppetlabs/code/environments/production/data/common.yaml nginx::worker_processes: 4 nginx::enable_ssl: false # /etc/puppetlabs/code/environments/production/data/nodes/web-server-01.yaml nginx::worker_processes: 8 nginx::enable_ssl: true模块中使用lookup函数获取数据:
class nginx { $worker_processes = lookup('nginx::worker_processes', Integer, 'first', $facts['processors']['count']) $enable_ssl = lookup('nginx::enable_ssl', Boolean, 'first', false) # 配置逻辑... }管理复杂应用配置
单个服务的配置相对简单,但实际生产环境往往需要管理整个应用栈。我们来看一个更复杂的例子:LAMP环境的配置。
创建profile模块
# profiles/manifests/lamp.pp class profiles::lamp { include apache include mysql include php # 确保安装顺序 Class['mysql'] -> Class['apache'] -> Class['php'] }Apache模块
class apache ( String $document_root = '/var/www/html', Array[String] $modules = ['rewrite', 'ssl'], ) { package { 'httpd': ensure => installed, } service { 'httpd': ensure => running, enable => true, } file { '/etc/httpd/conf/httpd.conf': ensure => present, content => template('apache/httpd.conf.erb'), notify => Service['httpd'], require => Package['httpd'], } $modules.each |$module| { exec { "enable-${module}-module": command => "/usr/bin/a2enmod ${module}", unless => "/usr/bin/apache2ctl -M | grep ${module}", notify => Service['httpd'], require => Package['httpd'], } } }使用角色分离
在大型环境中,不同服务器承担不同角色。可以创建role模块:
# roles/manifests/webserver.pp class roles::webserver { include profiles::lamp include profiles::monitoring include profiles::backup } # roles/manifests/database.pp class roles::database { include profiles::mysql include profiles::monitoring include profiles::backup }然后在site.pp中按角色分配:
node /^web-\d+\.example\.com$/ { include roles::webserver } node /^db-\d+\.example\.com$/ { include roles::database }配置文件管理最佳实践
使用文件片段拼接
有时候配置文件需要从多个模块贡献内容,比如nginx的虚拟主机配置:
# 主配置 concat { '/etc/nginx/nginx.conf': owner => 'root', group => 'root', mode => '0644', notify => Service['nginx'], } concat::fragment { 'nginx-main': target => '/etc/nginx/nginx.conf', content => template('nginx/nginx-main.conf.erb'), order => '01', } # 虚拟主机配置 define nginx::vhost ( String $document_root, String $server_name = $title, ) { concat::fragment { "nginx-vhost-${title}": target => '/etc/nginx/nginx.conf', content => template('nginx/vhost.conf.erb'), order => '10', } }敏感数据处理
生产环境中经常需要处理密码等敏感信息。Puppet支持加密的eyaml:
# 安装hiera-eyaml /opt/puppetlabs/puppet/bin/gem install hiera-eyaml创建加密的配置:
eyaml encrypt -s 'mysecretpassword'在Hiera中使用:
mysql::root_password: > ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAE...]大规模部署策略
管理几百台服务器时,需要考虑部署策略,避免同时更新所有服务器导致服务中断。
使用环境分离
# 创建不同环境 mkdir -p /etc/puppetlabs/code/environments/{development,staging,production}Agent可以指定环境:
# puppet.conf [agent] environment = staging分批次部署
可以使用Puppet的runinterval和splay参数控制Agent运行时间:
[agent] runinterval = 1800 # 30分钟运行一次 splay = true # 随机延迟,避免同时运行也可以手动控制部署:
# 禁用自动运行 puppet agent --disable "maintenance window" # 手动触发特定节点 mco puppet runonce -I web-server-01配置验证
部署前最好验证配置语法:
# 验证语法 puppet parser validate manifests/init.pp # 模拟运行 puppet agent --test --noop监控和故障排除
生产环境中,监控Puppet运行状态很重要。我们可以从多个维度监控:
日志分析
Puppet的日志很详细,但需要重点关注几个方面:
# Agent日志 tail -f /var/log/puppetlabs/puppet/puppet.log # Master日志 tail -f /var/log/puppetlabs/puppetserver/puppetserver.log关键指标包括:
配置编译时间
资源应用成功率
证书问题
依赖关系错误
使用PuppetDB
PuppetDB可以存储所有节点的状态信息,方便查询和监控:
# 安装PuppetDB yum install -y puppetdb puppetdb-termini # 配置Master连接PuppetDB vim /etc/puppetlabs/puppet/puppetdb.conf [main] server_urls = https://puppetdb.example.com:8081查询节点状态:
# 查看失败的节点 curl -X GET http://puppetdb:8080/pdb/query/v4/reports \ --data-urlencode 'query=["=", "status", "failed"]'常见问题排查
我在使用过程中遇到过几个典型问题:
证书过期:Puppet证书默认5年有效期,过期后Agent无法连接Master。需要重新签发证书。
依赖关系循环:资源之间的依赖关系形成循环,导致配置无法应用。可以通过puppet agent --graph生成依赖图分析。
文件权限问题:特别是SELinux环境下,需要注意文件的安全上下文。
内存不足:Master编译大量配置时可能内存不足,需要调整JVM参数。
与其他工具集成
Puppet可以和很多运维工具集成,形成完整的自动化体系。
与Git集成
使用r10k或Code Manager可以实现Git驱动的部署:
# Puppetfile mod 'puppetlabs-stdlib' mod 'puppetlabs-concat' mod 'nginx', :git => 'https://github.com/company/puppet-nginx.git', :branch => 'production'与监控系统集成
可以在Puppet配置中自动部署监控:
class profiles::monitoring { package { 'zabbix-agent': ensure => installed, } file { '/etc/zabbix/zabbix_agentd.conf': ensure => present, content => template('monitoring/zabbix_agentd.conf.erb'), notify => Service['zabbix-agent'], } service { 'zabbix-agent': ensure => running, enable => true, } }性能优化经验
管理大量服务器时,性能优化很重要。我总结了几个优化点:
Master端优化
# /etc/puppetlabs/puppetserver/conf.d/puppetserver.conf jruby-puppet: { max-active-instances: 4 max-requests-per-instance: 100000 }Agent端优化
[agent] usecacheonfailure = false report = false pluginsync = false对于只读节点,可以禁用一些不必要的功能。
网络优化
使用本地Package仓库可以大幅提升安装速度:
yumrepo { 'local-repo': baseurl => 'http://repo.internal.com/centos/7/', enabled => 1, gpgcheck => 0, }经过几个月的实践,我们的服务器配置管理效率提升了至少10倍,配置漂移问题基本消失。虽然初期学习成本比较高,但是长期收益非常明显。
特别是在云环境下,服务器经常弹性伸缩,Puppet的自动化配置管理能力显得更加重要。新服务器启动后几分钟就能自动完成所有配置,大大提升了运维效率。
当然Puppet也不是万能的,对于一些复杂的业务逻辑,还是需要结合其他工具。但作为基础设施配置管理,Puppet确实是个不错的选择。
如果你也在管理大量服务器,强烈建议试试Puppet。虽然学习曲线比较陡峭,但掌握后真的会让你的运维工作轻松很多。记住,好的工具能让运维工作事半功倍,而不是增加复杂度。