puppet使用详解
前言
随着企业服务器规模的不断扩大,再想通过手动去管理服务器已经变得越来越浪费时间,而且人总是容易出错的。所有就需要一款合适的自动化运维工具来管理服务器,自动配置服务器的工作。
puppet是一种Linux、Unix、windows平台的集中配置管理系统,使用自有的puppet描述语言,可管理配置文件、用户、cron任务、软件包、系统服务等。
puppet采用C/S星状的结构,所有的客户端和一个或几个服务器交互。每个客户端周期的(默认半个小时)向服务器发送请求,获得其最新的配置信息,保证和该配置信息同步。每个puppet客户端每半小时(可以设置)连接一次服务器端, 下载最新的配置文件,并且严格按照配置文件来配置客户端. 配置完成以后,puppet客户端可以反馈给服务器端一个消息. 如果出错,也会给服务器端反馈一个消息.
puppet结构
puppet支持两种运行模式:
- standalone模式:在单台服务器上制定规则,只能在单台服务器运行。
- master/agent模式:master制定规则,可以推送到多台agent服务器上运行。
puppet命令使用方法:
puppet help:列出所有帮助信息
puppet describe:列出puppet的资源类型
puppet apply:用于执行清单
puppet agent:puppet的agent模式下执行方法
puppet master:puppet的master模式下命令执行方法
...
puppet调用清单文件:
puppet apply -v -d --noop file.pp
-v:表示显示详细信息,--verbose
-d:显示调试信息,--debug
--noop:只是测试执行,查看是否有错误,并不真正执行
puppet规则写法
puppet支持5种核心规则:
user
name:指定用户名
gid:指定属组
groups:指定附加组
comment:注释
expiry:过期时间
home:家目录
system [true|false]:是否为系统用户
ensure [|present|absent]:添加还是删除用户
password:加密后的密码
group
name:组名
system:是否为系统组
ensure:添加还是删除用户,和user用法相同
members:成员用户
gid:组id
service
ensure:服务状态,有如下几种:running,stopped
enable:开机是否自动启动,true表示开机启动,false表示开机不启动
name:服务名
path:脚本搜索路径,默认为/etc/init.d/
start:手动定义服务启动命令
stop:手动定义服务关闭命令
status:
restart:定义服务重启命令,生产环境不建议服务重启,所有如果服务支持reload,此处可以指定为reload
package
name:安装包名
ensure:安装还是卸载,installed表示安装,latest表示安装最新版本,absent表示卸载,present也表示安装
source:包的安装路径,仅不能通过yum安装的包才需要指定,如本地的rpm包等
file
absent:指定文件类型,file为文件,directory为目录,link为链接
path:文件存放路径
source:从哪里复制文件到path路径
content:文件内容,可以配合template自动生成
owner:属主
group:属组
mode:权限
target:如果类型为链接,则链接的原文件在此指定
atime/ctime/mtime:指定时间戳
exec
command:要执行的命令
cwd:命令执行时的工作路径
creates:用于创建目录,此处指定的目录如果存在则不创建
path:指定命令存在路径
user/group:以哪个用户或者组的身份执行命令
onlyif:只有此处指定的命令成功执行command中的命令才执行
unless:和onlyif相反,只有此命令不执行command中的命令才执行
refresh:重新执行当前command的替代命令
refreshonly:仅接收到订阅的资源的通知是才执行,和subscribe一块使用
cron
command:要定期执行的命令
ensure:present表示添加任务计划,absent表示删除任务计划
hour:小时
minute:分钟
monthday:月
weekday:周
user:以哪个用户的身份执行
target:添加哪个用户的周期性任务
name:周期性任务名字
规则写法
type{'name':
执行语句1,
执行语句2,
...
}
例子:
file{'httpd.conf':
path => '/etc/httpd/conf/httpd.conf',
source => '/root/manifests/httpd.conf',
ensure => file,
notify => Service['httpd'],
}
puppet各个规则之间的依赖关系
- require:表示依赖于某规则
- before:先于某规则运行
- notify:发生变更之后通知某规则
- subscribe:监控某规则,当其发生变更则触发自身
例子:
file{'test.txt':
path => '/tmp/test.txt',
ensure => file,
source => '/etc/fstab',
}
file{'test.symlink':
path => '/tmp/test.symlink',
ensure => link,
target => '/tmp/test.txt',
require => File['test.txt'],
}
file{'test.dir':
path => '/tmp/test.dir',
ensure => directory,
source => '/etc/yum.repos.d/',
recurse => true,
}
注意:
依赖关系写法:before => File['test.txt'],需要采用如上写法,即type的第一个字母大写,规则名用中括号和单引号括起来。
puppet的变量
puppet支持丰富的变量,通过facter -p命令可以获取到本机的所有变量参数,各种硬件信息等,不过前提需要安装“facter-2.4.6-1.el7.x86_64.rpm”包。puppet也支持自定义变量。
变量定义方法:
$variable_name = value
变量支持的类型:
- 数值型:默认均识别为字符串,仅在数值上下文才以数值对待;
- 字符型:引号可有可无;但单引号为强引用,双引号为弱引用;
- 数组:[]中以逗号分隔元素列表;
- 布尔型:true,false
- hash:{}中以逗号分隔k/v数据列表; 键为字符型,值为任意puppet支持的类型;{ 'mon' => 'Monday', 'tue' => 'Tuesday', };
- undef:未定义 ;
正则表达式
(?i-mx:PATTERN)
其中:
i:区分大小写
-m:不以.当做换行符
-x:忽略PATTERN种的空白字符
puppet的流程控制语句
puppet支持if,case和selector等流程控制语句:
if语句
if $osfamily =~ /(?i-mx:debian)/ {
$webserver = 'apache2'
} else {
$webserver = 'httpd
}
表示判断osfamily变量是否匹配debian,其中debian不区分大小写,如果匹配则$webserver的值为apache2,否则为httpd。
case语句
case $osfamily {
"RedHat": { $webserver='httpd' }
/(?i-mx:debian)/: { $webserver='apache2' }
default: { $webserver='httpd' }
}
表示如果osfamily变量匹配为RedHat,则webserver变量值为httpd,如果匹配debian,debian不区分大小写,则webserver值为apache2,否则默认为httpd。
selector语句
$pkgname = $operatingsystem ? {
/(?i-mx:(ubuntu|debian))/ => 'apache2',
/(?i-mx:(redhat|fedora|centos))/ => 'httpd',
default => 'httpd',
}
表示判断$operatingsystemc的值如果为不区分大小写的ubuntun或者debian,则$pkgname的值为apache2,如果$operatingsystem的值为不区分大小写的redhat,fedora,centos,则$pkgname的值为httpd,否则默认为httpd。selector相对于case来说更加简洁。
puppet的模板使用
在puppet中可以定义模板文件,模板文件是以.erb结尾的,模板文件和普通文件的区别是其内部可以使用变量值。所以当agent获取到模板文件的时候可以根据系统自身的一些参数动态设定所需要的值。
例子:
这是一个nginx.conf的配置模板,可以看到work_processes的值为一个变量值,其表示根据系统的cpu数量自动设定运行进程数。
模板使用方法:
class nginx::webproxy inherits nginx {
file {'nginx.conf':
path => '/etc/nginx/nginx.conf',
content => template('nginx/nginx-webproxy.conf.erb'), #此处用centent代替path,表示获取模板文件作为配置文件。
}
Package['nginx'] -> File['nginx.conf'] ~> Service['nginx']
}
puppet的类
类是puppet中命名的代码模块,常用于定义一组通用目标的资源,可在puppet全局调用;类只有被调用才能够运行,有点类似于shell脚本中的函数。而且类可以被继承,也可以包含子类。
例子:
第一种调用方式:
class apache2 { #定义一个名字为apache2的类#
#判断operatingsystem的值来决定webpkg变量的值是什么#
$webpkg = $operatingsystem ? {
/(?i-mx:(centos|redhat|fedora))/ => 'httpd',
/(?i-mx:(ubuntu|debian))/ => 'apache2',
default => 'httpd',
}
package{"$webpkg":
ensure => installed,
}
file{'/etc/httpd/conf/httpd.conf':
ensure => file,
owner => root,
group => root,
source => '/tmp/httpd.conf',
require => Package["$webpkg"],
notify => Service['httpd'],
}
service{'httpd':
ensure => running,
enable => true,
}
}
include apache2 #调用apache2的类,类只有被调用才能执行#
第二种调用方式:
class dbserver($pkgname) { #首先定义一个名字为dbserver的类,此类有一个变量为$pkgname,不过此变量没有值#
package{"$pkgname":
ensure => latest,
}
service{"$pkgname":
ensure => running,
enable => true,
}
}
if $operatingsystem == "CentOS" {
$dbpkg = $operatingsystemmajrelease ? {
7 => 'mariadb-server',
default => 'mysqld-server',
}
}
class{'dbserver': #调用dbserver的类,给其pkgname变量赋值为$dbpkg#
pkgname => $dbpkg,
}
类的继承方式:
类的继承写法如下,子类执行时会先执行基类:
class 基类::子类 inherits 基类{
...puppet code...
...
}
例子:
class nginx { #定义基类#
package{'nginx':
ensure => installed,
}
service{'nginx':
ensure => running,
enable => true,
restart => '/usr/sbin/nginx -s reload',
}
}
class nginx::web inherits nginx { #定义一个名字为web的子类#
Service['nginx'] {
subscribe => File['ngx-web.conf'],
}
file{'ngx-web.conf':
path => '/etc/nginx/conf.d/ngx-web.conf',
ensure => file,
source => '/root/manifests/ngx-web.conf',
}
}
class nginx::proxy inherits nginx { #定义一个名字为proxy的子类#
Service['nginx'] {
subscribe => File['ngx-proxy.conf'],
}
file{'ngx-proxy.conf':
path => '/etc/nginx/conf.d/ngx-proxy.conf',
ensure => file,
source => '/root/manifests/ngx-proxy.conf',
}
}
include nginx::proxy #子类也需要调用才能执行#
puppet的模块使用
在复杂的环境之中,如果只想通过puppet的单个类或子类来进行工作是非常耗时耗力的,模块就是用来解决这个问题的。
puppet的模块是放在固定的目录下的,位于/etc/puppet/modules目录下,其由一组固定格式的目录组成:
- files:存放所有需要调用的文件;
- templates:存放所有可以被调用的模板文件,puppet的模板文件后缀为erb;
- manifests:存放清单规则文件,必须包含一个init.pp的清单文件,而且此清单文件定义的类名必须和模块名相同;
- lib:插件目录,常用于存储自定义的facts以及自定义类型;
- tests:当前模块的使用帮助或使用范例文件;
- spec:类似于tests目录,存储lib/目录下插件的使用帮助和范例;
模块在standalone模式下调用方法如下:
puppt apply -v -d --e 'include nginx::proxy'
此处例子表示调用的是子类,调用主类的方法和调用子类相同。
注意:
puppet3.6之后版本,不能在init.pp中使用import导入子类的,要调用子类需要在manifests目录下创建和子类名字相同的pp文件,然后执行的时候直接调用子类就可以了。
模块中模板和文件的调用方法:
- content => template('nginx/nginx-webproxy.conf.erb'),表示通过template直接调用模块名/模板名即可,不需要写完整路径
- source => 'puppet:///modules/tomcat/server.xml',此处表示文件的调用方法为puppet:///modules/模块名/文件名
puppet的master/agent执行模式
master/agent执行模式需要在master主机和agent主机分别安装不同的包,其通信过程是通过https来进行的。所以master和agent之间需要进行ssl证书文件的互相验证,验证通过才能相互通信。不过此https通信并不需要认为搭建ca等,puppet自己能够完成所有的工作。
当启动puppetmaster服务之后其会自动给自己生成私钥文件和证书文件,并且作为一个ca工作,当有agent连接上master之后,会自动给master发送一个证书申请文件。master可以手动或自动制作证书申请文件,然后master和agent就可以相互通信了。
注意:
master/agent模式必须采用主机名进行通信,所有内网需要有dns服务器进行主机名解析,如果没有的话就需要本地hosts文件进行解析。
master节点需要安装的安装包有:
puppet-server.noarch
facter-2.4.6-1.el7.x86_64.rpm
puppet.noarch
agent节点需要安装:
facter-2.4.6-1.el7.x86_64.rpm
puppet.noarch
安装完成之后可以直接启动服务,让master和agent运行在服务模式,也可以不让其运行在服务模式,而是运行在前台,方便学习者了解其通信过程,命令如下:
puppet master --no-daemonize --verbose
puppet agent --server master主机名 --no-daemonize --verbose
如果是直接启动服务,则agent需要修改其配置文件/etc/puppet/puppet.conf,在其中指定master是谁:
[agent]
# The file in which puppetd stores a list of the classes
# associated with the retrieved configuratiion. Can be loaded in
# the separate ``puppet`` executable using the ``--loadclasses``
# option.
# The default value is '$confdir/classes.txt'.
classfile = $vardir/classes.txt
# Where puppetd caches the local configuration. An
# extension indicating the cache format is added automatically.
# The default value is '$confdir/localconfig'.
localconfig = $vardir/localconfig
server = node5 #此处指定master主机名#
配置流程:
- 客户端指定master节点,启动服务
- master启动服务,客户端连接上来之后需要做客户端证书
puppet cert <action> [--all] [<host>]
action:
list:列出所有未制作证书
--all:列出所有已经制作证书
sign:签发证书
revoke:吊销证书
clean:吊销指定的客户端证书,并删除与其相关的所有文件
- master需要配置主机列表,指定不同的主机执行的模块,配置文件位于:/etc/puppet/manifests/site.pp,文件名必须为site.pp,内容如下:
node 'base' { #指定一个根节点,其他节点可以继承此节点,根节点表示所有节点都执行其指定模块#
include chrony
}
node /node[1-2]/ inherits base { #根据正则表达式匹配,也可以通过=精确指定,此处表示匹配node1和node2,其继承与base节点#
include nginx::webproxy
}
node /node[3-4]/ inherits base { #同上#
include proxyserver::proxyconf
include jdk
include tomcat::memcached
}
- 此时agent会应用master的配置,并且会每半小时来master同步一次配置
- master的所有模块文件都位于/etc/puppet/modules路径下
清单配置信息模块化组织方法
比如需要管理的主机非常多,例如tomcat有10台,mysql有5台,httpd有10台,这种情况下如果所有主机都写入site.pp文件会非常杂乱无章,此时可以通过模块化配置方式解决此问题,比如可以在/etc/puppet/manifests目录下创建mysql.d,httpd.d,tomcat.d目录,然后在其中写好各自的site.pp文件,然后在总site.pp文件中通过import命令导入即可。
当master发生变更通知agent方法
常规来说master发生变更之后如果要agent立即生效需要重启agent的服务,此方法非常不方便,可以通过如下配置定义master手动通知到agent节点更新配置:
- agent节点配置在/etc/puppet/puppet.conf配置如下信息:
[main]
# The Puppet log directory.
# The default value is '$vardir/log'.
logdir = /var/log/puppet
# Where Puppet PID files are kept.
# The default value is '$vardir/run'.
rundir = /var/run/puppet
# Where SSL certificates are kept.
# The default value is '$confdir/ssl'.
ssldir = $vardir/ssl
listen = true #表示agent本地开启监听,用于接收master的通知#
- 在/etc/puppet/auth.conf配置如下信息:
path /run #表示对/run路径做认证
method save #认证方式为save
auth any #对所有主机做认证
allow node5 #仅允许master主机
path /
auth any
- 当master发生变更之后通过如下命令通知agent即可
puppet kick --host agent_name
puppet配置多环境方法
通常企业都会有多套环境,如开发环境,测试环境和生产环境,不同环境的主机配置也不尽相同,那就需要配置多套环境进行管理。puppet 3.6版本之后配置如下:
- 编辑master的/etc/puppet/puppet.conf文件:
[master]
environmentpath = $confdir/environments #表示指定环境目录的路径,其中$confdir为puppet自身变量,表示为puppet的配置文件路径/etc/puppet/,通过puppet config print命令可以查看#
- 在多环境目录下为每一个环境准备一个子目录,如创建如下目录,然后就和之前使用puppet一样,不同生产环境的模块和site列表放入不同环境目录即可:
/etc/puppet/environments/production/{modules,manifests/site.pp} #生产环境
/etc/puppet/environments/test/{modules,manifests/site.pp} #测试环境
/etc/puppet/environments/development/{modules,manifests/site.pp} #开发环境
- agent在/etc/puppet/puppet.conf下配置如下:
[agent]
environment = { production|development | testing } #指定其属于哪个环境即可,其会自动应用指定环境的指定模块
总结
puppet的内容总体来说太多了,此处多有总结不到位的地方,还需要在此修改。