puppet简介
puppet是一种基于ruby语言开发的Lnux、Unix、windows平台的集中配置管理系统。它使用自有的puppet描述语言,可管理配置文件file、用户user、cron任务、软件包、系统服务等系统实体。
puppet依赖于C/S(客户端/服务器)的部署架构。它需要在puppet服务器上安装puppet-server软件包(以下简称master),在需要管理的目标主机上安装puppet客户端软件(以下简称client)。
为了保证安全,master和client之间是基于SSL和证书的,只有经过master证书认证的client才可以与master通信。
puppet是一个IT基础设施自动化管理工具,它能够帮助系统管理员管理基础设施的整个生命周期: 供应(provisioning)、配置(configuration)、联动(orchestration)及报告(reporting)。
基于puppet ,可实现自动化重复任务、快速部署关键性应用以及在本地或云端完成主动管理变更和快速扩展架构规模等。
遵循GPL 协议(2.7.0-), 基于ruby语言开发。
2.7.0 以后使用(Apache 2.0 license)
对于系统管理员是抽象的,只依赖于ruby与facter。
能管理多达40 多种资源,例如:file、user、group、host、package、service、cron、exec、yum repo等。
puppet工作机制
工作模型
puppet 通过声明性、基于模型的方法进行IT自动化管理。
定义:通过puppet 的声明性配置语言定义基础设置配置的目标状态;
模拟:强制应用改变的配置之前先进行模拟性应用;
强制:自动、强制部署达成目标状态,纠正任何偏离的配置;
报告:报告当下状态及目标状态的不同,以及达成目标状态所进行的任何强制性改变;
puppet三层模型如下:
工作流程
使用模型
puppet的使用模型分为单机使用模型和master/agent模型,下面我们来看看这两个模型的原理图。
单机使用模型
实现定义多个manifests –> complier –> catalog –> apply
master/agent模型
master/agent模型实现的是集中式管理,即 agent 端周期性向 master 端发起请求,请求自己需要的数据。然后在自己的机器上运行,并将结果返回给 master 端。
架构和工作原理如下:
工作原理
1、客户端puppet调用fast探测出主机的一些变量,如主机名、内存大小、IP地址等。Puppet把这些信息使用SSL连接发送给服务器端;
2、服务器端的puppetmaster通过fast工具分析检测客户端的主机名,然后找到项目的主配置文件manifest里面对应的node配置,并对该部分内容进行解析,fast发送过来的信息可以作为变量处理,node牵扯到的代码才被解析,没牵扯到的不解析,解析分为语法检查,如果语法没错,继续解析,解析结果生成一个结果‘伪代码’,然后把‘伪代码’发给客户端;
3、客户端收到‘伪代码’并且执行,客户端把执行结果发给服务器;
4、服务器端把客户端的执行结果写入日志。
在实际使用中多使用master/agent模型。
安装部署
配置4台服务器在同一局域网中1
2
3
410.186.61.39 ntpserver
10.186.61.103 master
10.186.60.60 node01
10.186.65.43 node01
并修改相应的主机名
安装NTP Server
由于Puppet需要使用SSL证书,依赖时间同步,所有需要搭建NTP服务器。
关闭所有服务器的防火墙和安全性策略1
2
3systemctl stop firewalld.service
systemctl disable firewalld.service
setenforce 0
安装NTP Server参考:搭建内网NTP时间服务器
然后master、node01、node02进行时间同步操作
修改hosts文件
master、node01、node02都进行此操作1
2
3
4vim /etc/hosts #添加
10.186.61.103 master
10.186.60.60 node01
10.186.65.43 node01
安装master端
1 | yum install -y epel-replease #安装epel源 |
启动master程序1
2systemctl enable puppetmaster.service
systemctl start puppetmaster.service
安装client端
node01、node02进行一样的操作1
2yum install -y epel-replease #安装epel源
yum install -y puppet #yum安装puppet控制端
编辑puppet配置文件1
2
3
4vim /etc/puppet/puppet.conf
[main]
server = master #main中添加
......
启动1
2
3systemctl enable puppet
systemctl start puppet
systemctl status puppet
client端申请证书1
2
3
4
5
6
7
8puppet agent --server=master --no-daemonize --verbose #两个client端执行命令一样
#执行完会有如下提示:
Info: Creating a new SSL key for nide01
Info: Caching certificate for ca
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for node01
Info: Certificate Request fingerprint (SHA256): 9E:E6:4D:3F:5B:03:D2:72:08:FF:0B:E7:92:48:45:FA:B7:2C:89:B5:12:CB:EC:8F:2E:50:B4:02:5F:4C:DF:17
Info: Caching certificate for ca
等待一会儿按ctrl+c组合键结束
授权
在master段查看申请证书的客户端1
2
3# puppet cert list
"node01" (SHA256) 19:C7:34:73:78:4C:6E:FA:5D:1D:BE:84:05:50:2F:B4:F1:13:8C:75:E2:DA:0C:3A:9D:46:89:2F:53:86:AB:BC
"node02" (SHA256) 07:48:B5:06:53:D7:A5:70:EF:06:A0:0D:D5:FA:8A:53:94:FB:69:07:E1:C2:59:18:8E:52:80:4D:B5:66:FC:90
将未申请的客户端进行授权
单个签署1
puppet cert sign clientname
全部签署1
2
3
4
5# puppet cert sign --all
Notice: Signed certificate request for node01
Notice: Removing file Puppet::SSL::CertificateRequest node01 at '/var/lib/puppet/ssl/ca/requests/node01.pem'
Notice: Signed certificate request for node02
Notice: Removing file Puppet::SSL::CertificateRequest node02 at '/var/lib/puppet/ssl/ca/requests/node02.pem'
查看已经申请注册的客户端1
2
3
4
5# ll /var/lib/puppet/ssl/ca/signed/
total 12
-rw-r--r-- 1 puppet puppet 1927 Feb 27 15:31 master.pem
-rw-r--r-- 1 puppet puppet 1927 Feb 27 15:41 node01.pem
-rw-r--r-- 1 puppet puppet 1927 Feb 27 15:41 node02.pem
可以看到已注册的包括master本身,一共三台服务器
至此Puppet部署已完成。
puppet使用方法
puppet 名词解释
- 资源:是puppet的核心,通过资源申报,定义在资源清单中。相当于ansible中的模块,只是抽象的更加彻底。
- 类:一组资源清单。
- 模块:包含多个类。相当于ansible中的角色。
- 站点清单:以主机为核心,应用哪些模块。
定义资源
puppet从以下三个维度来都资源完成抽象:
1、相似的资源被抽象成同一种资源“类型,”如程序包资源、用户资源及服务资源等
2、将资源属性或状态的描述与其实现方式剥离开来,如仅说明安装一个程序包而不用关系其具体是yum、pkgadd、prots或其他方式实现
3、仅描述资源的目标状态,也即期望其实现的结果,而不是其具体过程,如“确定nginx运行起来”,而不是具体描述为“运行nginx命令将启动起来”
这三个也被称为puppet的资源抽象层(RAL)。RAL由type(类型)和provide(提供者,即不同的OS上的特定实现)组成。
资源是puppet用于模型化系统配置的基础单元,每个资源都从某个角度描述了系统属性,如某程序包必须安装或某用户必须移除等,在puppet,用于完成此类功能的代码也即“资源申报”1
2
3
4
5type { ‘title’:
atttibue1 => value1,
atttibue2 => value2,
......
}
注意:
资源的文件统一以.pp结尾。
type必须使用小写字符;title是一个字符串,在同一类型中必须惟一;每一个属性之间需要用“,”隔开,最后一个“,”可省略。
例如,可以同时有名为nginx 的“service”资源和“package”资源,但在“package” 类型的资源中只能有一个名为“nginx”的资源。
资源属性中的三个特殊属性
- Namevar:可简称为name;
- ensure:资源的目标状态;
- Provider:指明资源的管理接口;
常见资源介绍
查看资源
我们可以使用puppet describe来打印有关Puppet资源类型,提供者和元参数的帮助。使用语法如下:1
2
3USAGE
-----
puppet describe [-h|--help] [-s|--short] [-p|--providers] [-l|--list] [-m|--meta]
group:管理系统上的用户组。
查看使用帮助信息:1
puppet describe group -s -m
属性:
name:组名,可以省略,如果省略,将继承title的值;
gid:GID;
system:是否为系统组,true OR false;
ensure:目标状态,present/absent;
members:成员用户;
简单举例如下:1
2
3
4
5
6vim group.pp
group{'mygrp':
name => 'mygrp',
ensure => present,
gid => 2000,
}
运行:1
2
3
4
5
6
7
8
9
10
11
12
13# puppet apply -v --noop group.pp ##试运行
Notice: Compiled catalog for master in environment production in 0.13 seconds
Info: Applying configuration version '1551340533'
Notice: /Stage[main]/Main/Group[mygrp]/ensure: current_value absent, should be present (noop)
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 0.04 seconds
# puppet apply -v group.pp ##运行
Notice: Compiled catalog for master in environment production in 0.12 seconds
Info: Applying configuration version '1551340577'
Notice: /Stage[main]/Main/Group[mygrp]/ensure: created
Notice: Finished catalog run in 0.08 seconds
user:管理系统上的用户。
查看使用帮助信息:1
puppet describe user -s -m
属性:
name:用户名,可以省略,如果省略,将继承title的值;
uid: UID;
gid:基本组ID;
groups:附加组,不能包含基本组;
comment:注释;
expiry:过期时间 ;
home:用户的家目录;
shell:默认shell类型;
system:是否为系统用户 ;
ensure:present/absent;
password:加密后的密码串;
简单举例如下:1
2
3
4
5
6
7
8
9
10
11vim user.pp
user{'francis':
ensure => present,
system => false,
comment => 'Test User',
shell => '/bin/bash',
home => '/data/francis',
managehome => true,
groups => 'mygrp',
uid => 3000,
}
运行1
2
3
4
5
6
7
8
9
10
11
12# puppet apply -v --noop user.pp
Notice: Compiled catalog for master in environment production in 0.17 seconds
Info: Applying configuration version '1551341447'
Notice: /Stage[main]/Main/User[francis]/ensure: current_value absent, should be present (noop)
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Finished catalog run in 0.04 seconds
# puppet apply -v user.pp
Notice: Compiled catalog for master in environment production in 0.18 seconds
Info: Applying configuration version '1551341455'
Notice: /Stage[main]/Main/User[francis]/ensure: created
Notice: Finished catalog run in 0.09 seconds
package:puppet管理软件包
查看使用帮助信息:1
puppet describe package -s -m
属性:
ensure:installed, present, latest, absent, any version string (implies present)
name:包名,可以省略,如果省略,将继承title的值;
source:程序包来源,仅对不会自动下载相关程序包的provider有用,例如rpm或dpkg;
provider:指明安装方式;
简单举例如下:1
2
3
4
5vim package.pp
package{'httpd':
ensure => installed,
procider => yum
}
service:定义服务的状态
查看使用帮助信息:1
puppet describe service -s -m
属性:
ensure:服务的目标状态,值有true(running)和false(stopped)
enable:是否开机自动启动,值有true和false
name:服务名称,可以省略,如果省略,将继承title的值
path:服务脚本路径,默认为/etc/init.d/下
start:定制启动命令
stop:定制关闭命令
restart:定制重启命令
status:定制状态
file:管理文件、目录、软链接
查看使用帮助信息:1
puppet describe file -s -m
属性:
ensure:目标状态,值有absent,present,file,directory和link
file:类型为普通文件,其内容由content属性生成或复制由source属性指向的文件路径来创建;
link:类型为符号链接文件,必须由target属性指明其链接的目标文件;
directory:类型为目录,可通过source指向的路径复制生成,recurse属性指明是否递归复制;
path:文件路径;
source:源文件;
content:文件内容;
target:符号链接的目标文件;
owner:定义文件的属主;
group:定义文件的属组;
mode:定义文件的权限;
atime/ctime/mtime:时间戳;
exec:执行命令
慎用,通常用来执行外部命令
查看使用帮助信息:1
puppet describe exec -s -m
属性:
command(namevar):要运行的命令;
cwd:指定运行该命令的目录;
creates:文件路径,仅此路径表示的文件不存在时,command方才执行;
user/group:运行命令的用户身份;
path:指定命令执行的搜索路径;
onlyif:此属性指定一个命令,此命令正常(退出码为0)运行时,当前command才会运行;
unless:此属性指定一个命令,此命令非正常(退出码为非0)运行时,当前command才会运行;
refresh:重新执行当前command的替代命令;
refreshonly:仅接收到订阅的资源的通知时方才运行;
简单举例如下:1
2
3
4
5
6vim exec.pp
exec{'cmd':
command => 'mkdir /data/testdir',
path => ['/bin','/sbin','/usr/bin','/usr/sbin'],
# path => '/bin:/sbin:/usr/bin:/usr/sbin',
}
cron:定义周期性任务
查看使用帮助信息:1
puppet describe cron -s -m
属性:
command:要执行的任务(命令或脚本);
ensure:目标状态,present/absent;
hour:时;
minute:分;
monthday:日;
month:月;
weekday:周;
user:以哪个用户的身份运行命令(默认为root);
target:添加为哪个用户的任务;
name:cron job的名称;
简单举例如下:1
2
3
4
5
6
7vim cron.pp
cron{'timesync':
command => '/usr/sbin/ntpdata 10.186.61.39',
ensure => present,
minute => '*/3',
user => 'root',
}
运行:1
2
3
4
5
6
7
8
9
10
11
12
13
14# puppet apply -v --noop cron.pp
Notice: Compiled catalog for master in environment production in 0.08 seconds
Info: Applying configuration version '1551344167'
Notice: /Stage[main]/Main/Cron[timesync]/ensure: current_value absent, should be present (noop)
Notice: Class[Main]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 1 events
Notice: Finished catalog run in 0.10 seconds
# puppet apply -v cron.pp
Notice: Compiled catalog for master in environment production in 0.08 seconds
Info: Applying configuration version '1551344175'
Notice: /Stage[main]/Main/Cron[timesync]/ensure: created
Notice: Finished catalog run in 0.08 seconds
[root@master manifests]# crontab -l
*/3 * * * * /usr/sbin/ntpdata 10.186.61.39
notify:调试输出
查看使用帮助信息:1
puppet describe notify -s -m
属性:
message:记录的信息
name:信息名称
该选项一般用于master/agent模式中,来记录一些操作的时间,比如重新安装了一个程序呀,或者重启了应用等等。会直接输出到代理机的运行日志中。
资源的特殊属性
puppet中也提供了before、require、notify和subscribe四个参数来定义资源之间的依赖关系和通知关系。
before:表示需要依赖于某个资源
require:表示应该先执行本资源,在执行别的资源
notify:A notify B:B依赖于A,且A发生改变后会通知B;
subscribe:B subscribe A:B依赖于A,且B监控A资源的变化产生的事件;
同时,依赖关系还可以使用->和~>来表示:
-> 表示后资源需要依赖前资源
~> 表示前资源变动通知后资源调用tag 标签
如同 ansible 一样,puppet 也可以定义“标签”——tag,打了标签以后,我们在运行资源的时候就可以只运行某个打过标签的部分,而非全部。这样就更方便于我们的操作。
一个资源中,可以有一个tag也可以有多个。具体使用语法如下:1
2
3
4
5
6
7
8
9type{'title':
...
tag => 'TAG1',
}
type{'title':
...
tag => ['TAG1','TAG2',...],
}
调用时的语法如下:1
puppet apply --tags TAG1,TAG2,...
puppet 变量
puppet 变量以“$”开头,赋值操作符为“=”,语法为$variable_name=value。
数据类型:
字符型:引号可有可无;但单引号为强引用,双引号为弱引用;支持转义符;
数值型:默认均识别为字符串,仅在数值上下文才以数值对待;
数组:[]中以逗号分隔元素列表;
布尔型值:true, false;不能加引号;
hash:{}中以逗号分隔k/v数据列表; 键为字符型,值为任意puppet支持的类型;{ ‘mon’ => ‘Monday’, ‘tue’ => ‘Tuesday’, };
undef:从未被声明的变量的值类型;
正则表达式:
(?<ENABLED OPTION>:<PATTERN>)
(?-<DISABLED OPTION>:<PATTERN>)
OPTIONS:
i:忽略字符大小写;
m:把.当换行符;
x:忽略<PATTERN>中的空白字符;
(?i-mx:PATTERN)
注意:不能赋值给变量,仅能用在接受=~或!~操作符的位置;
puppet的变量种类
puppet 种类有三种,为facts,内建变量和用户自定义变量。1
2
3
4
5
6
7
8
9
10facts:
由facter提供;top scope;
内建变量:
master端变量
$servername, $serverip, $serverversion
agent端变量
$clientcert, $clientversion, $environment
parser变量
$module_name
用户自定义变量
变量的作用域
不同的变量也有其不同的作用域。我们称之为Scope。
作用域有三种,top scope,node scope,class scope。
其生效范围排序为:top scope > node scope > class scope
其优先级排序为:top scope < node scope < class scope
puppet 流程控制语句
puppet 支持if 语句,case 语句和selector 语句。
if 语句
if语句支持单分支,双分支和多分支。具体语法如下:
单分支:1
2
3
4if CONDITION {
statement
……
}
双分支:1
2
3
4
5
6
7
8if CONDITION {
statement
……
}
else{
statement
……
}
多分支:1
2
3
4
5
6
7
8
9
10
11
12if CONDITION {
statement
……
}
elsif CONDITION{
statement
……
}
else{
statement
……
}
其中,CONDITION的给定方式有如下三种:
- 变量
- 比较表达式
- 有返回值的函数
case 语句
类似 if 语句,case 语句会从多个代码块中选择一个分支执行,这跟其它编程语言中的 case 语句功能一致。
case 语句会接受一个控制表达式和一组 case 代码块,并执行第一个匹配到控制表达式的块。
使用语法如下:1
2
3
4
5
6
7case CONTROL_EXPRESSION {
case1: { ... }
case2: { ... }
case3: { ... }
……
default: { ... }
}
其中,CONTROL_EXPRESSION的给定方式有如下三种:
- 变量
- 表达式
- 有返回值的函数
各case的给定方式有如下五种:
- 直接字串;
- 变量
- 有返回值的函数
- 正则表达式模式;
- default
selector语句
Selector 只能用于期望出现直接值(plain value) 的地方,这包括变量赋值、资源属性、函数参数、资源标题、其它 selector。
selector 不能用于一个已经嵌套于于selector 的case 中,也不能用于一个已经嵌套于case 的case 语句中。
具体语法如下:1
2
3
4
5
6CONTROL_VARIABLE ? {
case1 => value1,
case2 => value2,
...
default => valueN,
}
其中,CONTROL_EXPRESSION的给定方式有如下三种:
- 变量
- 表达式
- 有返回值的函数
各case的给定方式有如下五种:
- 直接子串;
- 变量;
- 有返回值的函数;
- 正则表达式模式;
- default
selectors 使用要点:
- 整个selector 语句会被当作一个单独的值,puppet 会将控制变量按列出的次序与每个case 进行比较,并在遇到一个匹配的 case 后,将其值作为整个语句的值进行返回,并忽略后面的其它 case。
- 控制变量与各 case 比较的方式与 case 语句相同,但如果没有任何一个 case 与控制变量匹配时,puppet 在编译时将会返回一个错误,因此,实践中,其必须提供default case。
- selector 的控制变量只能是变量或有返回值的函数,切记不能使用表达式。
- 其各 case 可以是直接值(需要加引号) 、变量、能调用返回值的函数、正则表达式模式或 default。
- 但与 case 语句所不同的是,selector 的各 case 不能使用列表。
- selector 的各 case 的值可以是一个除了 hash 以外的直接值、变量、能调用返回值的函数或其它的 selector。
puppet的类
Class是用于通用目标或目的的一组资源,因此,它是命令的代码块,在某位置创建之后可在puppet全局使用。类似于其他编程语言中的类的功能,puppet的类可以继承,也可以包含子类,定义类的语法如下所示1
2
3class my_class {
...puppet code ...
}
例如:定义一个名为nginx的类牟其中包含两类资源,一个是package类型的nginx,一个是service的nginx1
2
3
4
5
6
7
8
9
10
11class nginx {
package { 'nginx':
ensure => installed,
name => nginx,
}
service { 'nginx':
ensure => true,
enable => true,
subscribe => Package['nginx'],
}
}
以上是类的定义,类似于函数。需要使用的话,要调用。调用时,使用关键在include即可。
类的继承:
类可以基于父类调用,在调用时,应该指定通过inherits关键字调用父类。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14class nginx {
package { 'nginx':
ensure => installed,
name => nginx,
}
}
class nignx::web inherits nginx {
service { 'nginx':
ensure => true,
enable => true,
}
}
include nignx::web
也支持类的覆盖和重写:1
2=>:在子类中覆盖父类中的资源
+>:在子类中为父类中的资源新增额外的属性
模板
puppet模块:为了实现某种完备功能而组织成的一个独立的、自我包含的目录结构
模块名:目录名1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20目录结构:
Module_name:
manifests
init.pp: 必须声明一个类,类名与模块名相同;
*.pp:
MODULE_NAME::[SUBDIR_NAME]::MANIFESTS_FILE_NAME
files:静态文件
puppet url:puppet:///modules/MODULE_NAME/[SUBDIR_NAME]/FILE_NAME
file{'nginx.conf':
source => puppet:///modules/nginx/nginx.conf
}
templates: 模板文件:*.erb
template('MODULE_NAME/TEMPLATE_FILE_NAME');
file{'nginx.conf':
content => template('模板文件'),
}
lib: 插件
tests: 模块使用说明文档
spec: lib目录下的插件使用说明文档
使用范例
使用maste/agent模式,安装nginx
master端
modules下文件路径和目录如下:1
2
3
4
5
6
7
8
9
10# pwd
/etc/puppet/modules/nginx
[root@master nginx]# tree
.
├── files
│ └── nginx.conf
└── manifests
└── init.pp
2 directories, 2 files
文件内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# cat manifests/init.pp
class nginx {
package{'nginx':
ensure => installed,
allow_virtual => false,
}
file{'nginx.conf':
ensure => file,
source => 'puppet:///modules/nginx/nginx.conf',
require => Package['nginx'],
path => '/etc/nginx/nginx.conf',
}
service{'nginx':
ensure => true,
enable => true,
require => Package['nginx'],
subscribe => File['nginx.conf'],
}
}
nginx.conf的内容为nginx的配置文件
注意:puppet:///modules/nginx/nginx.conf #不需要写files目录,指定模块文件后puppet默认回去files目录下找对应的文件。
manifests下目录和内容:1
2
3
4
5
6
7
8# pwd
/etc/puppet/manifests
# cat site.pp
import "server/*.pp"
# cat server/node01.pp
node 'node01' {
include nginx
}
agent端
测试:1
2
3
4
5
6# puppet agent -t --server=master
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for node02
Info: Applying configuration version '1551431554'
Notice: Finished catalog run in 0.18 seconds
1 | # ps -ef|grep nginx |
不需要重启agent端,master端每隔30秒会自动推送。
可以看到nginx已经安装成功并启动,端口监听正常。
写到最后我不推荐大家用puppet!