Puppet
puppet是一种linux,unix,windows平台的集中配置管理系统,尽管puppet采用ruby开发,但是puppet的配置语言却自成一套编程语言体系(puppet描述语言),puppet可以自行维护一个相对稳定的IT系统,采用c/s星状的结构,也就是master/agent框架,每个puppet-agent会周期(默认半个小时)向服务器发送请求,获取最新的配置信息,保障每个puppet-agent系统都可以根据puppet-master的配置维护系统稳定和配置的一致性,配置完成后puppet-agent可以反馈给服务端一个消息。
puppet的配置语言是基于声明性的编程语言进行配置,在puppet的工作模式中分为:
- 定义:使用pupet配置语言定义资源的状态
- 模拟:根据资源关系图,puppet可以模拟部署(无损运行测试代码)
- 强制:比对客户端主机状态和定义的资源状态是否一致,自动强制执行
- 报告:通过puppet api,可以将日志送到第三方监控工具,如:dashboard,forman
puppet将底层的资源进行抽象化,这些资源通过puppet的配置语言来进行事务处理这些抽象化的资源层,所以如果按照按照单一配置语言处理的过程来进行分层的话,我们还可以分为三层:
- 配置语言
- 事务层
- 资源抽象层:
- 资源类型:相似的资源被抽象为同一资源的类型,如程序包资源、用户资源及服务资源等,具体来说就是用户、组、文件、程序、服务等。
- 属性及状态与实现方式分离:仅说明安装一个程序包而不关心具体通过什么方式来实现。
- 期望状态:期望达到的结果,不必说明具体过程
puppet的核心就是资源,其具体的实现过程puppet都通过抽象层来完成,所以在配置puppet的过程中,我们的核心就是编写资源清单:manifest,及通过资源清单中资源定义的所依赖的文件、模版等数据按特定结构组织起即为的‘模块’。
puppet属于c/s架构,所以在agent与master的架构中我们需要安装不同的数据包:
agent:puppet,facter
master:puppet-server
需要获取的puppet包,我们可以通过这个url获取,http://yum.puppetlabs.com/
结下来我们可以展示下puppet的工作模型,一下是在agent下的工作模型:
而这个就是master-agent的工作模型:
Puppet的配置语言
我们为了探究puppet的配置语言,所以我们可以在agent的模式下测试自己的配置语言:
puppet的语法格式:Usage: puppet <subcommand> [options] <action> [options]
获取所支持的所有的资源类型:
1 | ~]# puppet describe -l #列出所有的资源类型 |
2 | ~]# puppet describe RESOURCE_TYPE #获取单个资源类型的属性 |
每个资源都应该有type、title、attributes,如:
1 | type {'title': |
2 | attribute1 => value1, |
3 | attribute2 => value2, |
4 | } |
注意:title必须在同一type中唯一,并且必须小写。
在资源的属性(attributes)中,除了资源本身的属性中,我们还可以为它定义以下属性:
- namevar: 大多数type都有在目标系统上标识资源的一个属性,这个常常被称为namevar,namevar的值在配的资源type中必须是唯一的,除了少数例外(exec)。
- ensure: 用于大多数资源中,用于控制资源的存在性
- metaparameters: 用于资源引用,资源的依赖关系,通知关系等。
常用的资源类型:user,group,file,package,service,exec,cron,notify
group
- name: namevar 组名
- gid: GID
- system: true|false
- ensure: present|absent
- members: 组内成员
example:
1 | ~]# cat group.pp |
2 | group { "jusene": |
3 | name => "jusene", |
4 | gid => 3000, |
5 | ensure => present, |
6 | } |
7 | ~]# puppet apply -v group.pp |
8 | Notice: Compiled catalog for init.localdomain in environment production in 0.11 seconds |
9 | Info: Applying configuration version '1505049462' |
10 | Notice: /Stage[main]/Main/Group[jusene]/ensure: created |
11 | Notice: Finished catalog run in 0.03 seconds |
12 | ~]# grep jusene /etc/group |
13 | jusene:x:3000: |
user
- comment: 注释信息
- ensure: true|false
- expiry: 过期期限
- gid: 基本组
- groups: 附加组
- home: 家目录
- shell: 默认shell
- name: namevar 用户名
- system: true|false
- uid: UID
- password: 这里需要的是加密后的密码
生成密码的方式
md5加密
1 | ~]# openssl passwd -1 -salt 'pass' |
2 | Password: |
3 | $1$pass$fPYxo9a/Tb6JgVP.kg1kV. |
sha512加密
1 | ~]# pip install -U passlib |
2 | ~]# python |
3 | Python 2.7.5 (default, Nov 20 2015, 02:00:19) |
4 | [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2 |
5 | Type "help", "copyright", "credits" or "license" for more information. |
6 | from passlib.hash import sha512_crypt |
7 | import getpass |
8 | print(sha512_crypt.encrypt(getpass.getpass())) |
9 | Password: |
10 | $6$rounds=656000$oQwcJxo9Leu63FFN$oqS901AxOw6kdE1b/tHuI6J5fhuYG42Xo9P6UmdMrqfkMM3Yx4iN1c07tpbzZP54H0R7Ey3AbDuq95/pievGX0 |
example:
1 | ~]# cat user.pp |
2 | user {'jusene': |
3 | name => 'jusene', |
4 | uid => 3000, |
5 | gid => 3000, |
6 | home => '/home/jusene', |
7 | shell => '/bin/bash', |
8 | comment => 'puppet create user', |
9 | ensure => present, |
10 | password => '$6$rounds=656000$oQwcJxo9Leu63FFN$oqS901AxOw6kdE1b/tHuI6J5fhuYG42Xo9P6UmdMrqfkMM3Yx4iN1c07tpbzZP54H0R7Ey3AbDuq95/pievGX0', |
11 | } |
12 | ~]# puppet apply -v user.pp |
13 | Notice: Compiled catalog for init.localdomain in environment production in 0.15 seconds |
14 | Info: Applying configuration version '1505050550' |
15 | Notice: /Stage[main]/Main/User[jusene]/ensure: created |
16 | Notice: Finished catalog run in 0.04 seconds |
17 | ~]# grep jusene /etc/passwd |
18 | jusene:x:3000:3000:puppet create user:/home/jusene:/bin/bash |
19 | ~]# grep jusene /etc/shadow |
20 | jusene:$6$rounds=656000$oQwcJxo9Leu63FFN$oqS901AxOw6kdE1b/tHuI6J5fhuYG42Xo9P6UmdMrqfkMM3Yx4iN1c07tpbzZP54H0R7Ey3AbDuq95/pievGX0:17419:0:99999:7::: |
file
管理文件的内容、从属关系以及权限,内容可以通过content属性直接给出,也可以通过source属性根据远程服务器路径下载生成:
- backup: .puppet.bak 覆盖前备份
- content: 直接给出文件内容,支持\n,\t
- source: 从指定位置下载文件,可以是本地文件路径(单机模式),也可以是puppet:///modules/module_name/file_name
- ensure: file,directory,link,present,absent
- force: 强制创建,可用值yes,no,true,false
- group: 属组
- owner: 属主
- mode: 权限,支持八进制格式权限,以及u,g,o的赋值方式
- path: namevar,绝对路径
- target: 当ensure为link时,target表示path指向的文件是一个符号文件,其目标为此target属性指向的路径
example:
1 | ~]# cat file.pp |
2 | file {'test': |
3 | path => '/tmp/fstab', |
4 | backup => '.puppet.bak', |
5 | source => '/etc/fstab', |
6 | owner => 'jusene', |
7 | group => 'jusene', |
8 | mode => '0666', |
9 | ensure => file, |
10 | } |
11 | ~]# puppet apply -v file.pp |
12 | Notice: Compiled catalog for init.localdomain in environment production in 0.11 seconds |
13 | Info: Applying configuration version '1505051798' |
14 | Notice: /Stage[main]/Main/File[test]/ensure: defined content as '{md5}c33fef818e0af833709ef902db780705' |
15 | Notice: Finished catalog run in 0.04 seconds |
16 | ~]# ll /tmp/fstab |
17 | -rw-rw-rw-. 1 jusene jusene 541 Sep 10 09:56 /tmp/fstab |
18 | ~]# echo '#' >> /etc/fstab |
19 | ~]# puppet apply -v file.pp |
20 | Notice: Compiled catalog for init.localdomain in environment production in 0.12 seconds |
21 | Info: Applying configuration version '1505051898' |
22 | Notice: /Stage[main]/Main/File[test]/content: content changed '{md5}c33fef818e0af833709ef902db780705' to '{md5}e26781ee354d18ad64e84427a765672c' |
23 | Notice: Finished catalog run in 0.04 seconds |
24 | ~]# ll /tmp/fstab |
25 | fstab fstab.puppet.bak |
example2:
1 | ~]# cat file1.pp |
2 | file {'test': |
3 | path => '/opt/fstab', |
4 | target => '/etc/fstab', |
5 | ensure => link, |
6 | } |
7 | ~]# puppet apply -v file2.pp |
8 | Notice: Compiled catalog for init.localdomain in environment production in 0.11 seconds |
9 | Info: Applying configuration version '1505052170' |
10 | Notice: /Stage[main]/Main/File[test]/ensure: created |
11 | Notice: Finished catalog run in 0.02 seconds |
12 | ~]# ll /opt/fstab |
13 | lrwxrwxrwx. 1 root root 10 Sep 10 10:02 /opt/fstab -> /etc/fstab |
exec
运行一个外部命令:命令应该具备“幂等性”:
幂等性:
– 命令本身具备幂等性,运行多少遍都无影响
– 资源有onlyif,unless,create等属性以实现命令的条件运行
– 资源有refreshonly的属性,以实现只有订阅的资源发生时才执行
- command:运行的命令 namevar
- creates:此属性指定的文件不存在时才运行
- cwd:此属性指定的路径下运行命令
- user:以指定的用户身份运行命令
- group:以指定的用户组身份运行命令
- onlyif:给定测定命令,仅在此命令返回true
- unless:给定测试命令,仅在此命令放回false
- refresh:接受其他资源发来的refresh通知时,默认时重新执行exec定义的command,refresh属性可改变这种行为,即可指定仅在refresh时运行的命令
- refreshonly:仅在收到refresh通知,才运行此资源
- returns:期望返回的返回值
- path:命令查找的路径
- tries:尝试执行的次数
- timeout:超时的时长
example:
1 | ~]# cat exec.pp |
2 | exec {"test": |
3 | command => "touch /tmp/test.file", |
4 | creates => '/tmp/test.file', |
5 | path => ['/usr/bin','/usr/sbin'], |
6 | user => 'jusene', |
7 | group => 'jusene', |
8 | tries => 2, |
9 | timeout => 5 |
10 | } |
11 | ~]# puppet apply -v exec.pp |
12 | Notice: Compiled catalog for init.localdomain in environment production in 0.05 seconds |
13 | Info: Applying configuration version '1505053485' |
14 | Notice: /Stage[main]/Main/Exec[test]/returns: executed successfully |
15 | Notice: Finished catalog run in 0.05 seconds |
16 | ~]# ll /tmp/test.file |
17 | -rw-r--r--. 1 jusene jusene 0 Sep 10 10:24 /tmp/test.file |
example2:
1 | ~]# cat exec1.pp |
2 | exec {"test": |
3 | command => "echo 'ok' > /tmp/test.file", |
4 | onlyif => "test -e /tmp/test.file", |
5 | path => ['/usr/bin','/usr/sbin'] |
6 | } |
7 | ~]# puppet apply -v exec1.pp |
8 | Notice: Compiled catalog for init.localdomain in environment production in 0.04 seconds |
9 | Info: Applying configuration version '1505054015' |
10 | Notice: /Stage[main]/Main/Exec[test]/returns: executed successfully |
11 | Notice: Finished catalog run in 0.06 seconds |
12 | ~]# cat /tmp/test.file |
13 | ok |
14 | ~]# > /tmp/test.file |
15 | ~]# cat exec2.pp |
16 | exec {"test": |
17 | command => "echo 'ok' > /tmp/test.file", |
18 | unless => "test -e /tmp/test.file", |
19 | path => ['/usr/bin','/usr/sbin'] |
20 | } |
21 | ~]# puppet apply -v exec2.pp |
22 | Notice: Compiled catalog for init.localdomain in environment production in 0.05 seconds |
23 | Info: Applying configuration version '1505054121' |
24 | Notice: Finished catalog run in 0.05 seconds |
25 | ~]# cat /tmp/test.file |
example3:
1 | ~]# cat exec3.pp |
2 | file {'test': |
3 | path => "/tmp/issue", |
4 | source => "/etc/issue", |
5 | ensure => file, |
6 | notify => Exec['test'] |
7 | } |
8 | |
9 | exec {'test': |
10 | command => "echo '1' > /tmp/test.file", |
11 | refresh => "echo '2' > /tmp/test.file", |
12 | path => ['/usr/bin','/usr/sbin'] |
13 | } |
14 | ~]# puppet apply -v exec3.pp |
15 | Notice: Compiled catalog for init.localdomain in environment production in 0.17 seconds |
16 | Info: Applying configuration version '1505054544' |
17 | Notice: /Stage[main]/Main/File[test]/ensure: defined content as '{md5}f078fe086dfc22f64b5dca2e1b95de2c' |
18 | Info: /Stage[main]/Main/File[test]: Scheduling refresh of Exec[test] |
19 | Notice: /Stage[main]/Main/Exec[test]/returns: executed successfully |
20 | Notice: /Stage[main]/Main/Exec[test]: Triggered 'refresh' from 1 events |
21 | Notice: Finished catalog run in 0.08 seconds |
22 | ~]# cat /tmp/test.file |
23 | 2 |
24 | ~]# puppet apply -v exec3.pp |
25 | Notice: Compiled catalog for init.localdomain in environment production in 0.19 seconds |
26 | Info: Applying configuration version '1505054582' |
27 | Notice: /Stage[main]/Main/Exec[test]/returns: executed successfully |
28 | Notice: Finished catalog run in 0.07 seconds |
29 | ~]# cat /tmp/test.file |
30 | 1 |
31 | ~]# cat exec4.pp |
32 | file {'test': |
33 | path => "/tmp/issue", |
34 | source => "/etc/issue", |
35 | ensure => file, |
36 | notify => Exec['test'] |
37 | } |
38 | |
39 | exec {'test': |
40 | command => "echo '1' > /tmp/test.file", |
41 | refreshonly => true, |
42 | path => ['/usr/bin','/usr/sbin'] |
43 | } |
44 | ~]# puppet apply -v exec3.pp |
45 | Notice: Compiled catalog for init.localdomain in environment production in 0.18 seconds |
46 | Info: Applying configuration version '1505054793' |
47 | Notice: /Stage[main]/Main/File[test]/ensure: defined content as '{md5}f078fe086dfc22f64b5dca2e1b95de2c' |
48 | Info: /Stage[main]/Main/File[test]: Scheduling refresh of Exec[test] |
49 | Notice: /Stage[main]/Main/Exec[test]: Triggered 'refresh' from 1 events |
50 | Notice: Finished catalog run in 0.08 seconds |
51 | ~]# cat /tmp/test.file |
52 | 1 |
53 | ~]# puppet apply -v exec3.pp |
54 | Notice: Compiled catalog for init.localdomain in environment production in 0.16 seconds #command的指令并没有没执行 |
55 | Info: Applying configuration version '1505054820' |
56 | Notice: Finished catalog run in 0.05 seconds |
57 | ~]# cat /tmp/test.file |
58 | 1 |
notify
打印信息
- message:要发送的消息的内容,namevar
example:
1 | ~]# cat notify.pp |
2 | notify {'test': |
3 | message => 'hello puppet' |
4 | |
5 | } |
6 | ~]# puppet apply -v notify.pp |
7 | Notice: Compiled catalog for init.localdomain in environment production in 0.01 seconds |
8 | Info: Applying configuration version '1505055101' |
9 | Notice: hello puppet |
10 | Notice: /Stage[main]/Main/Notify[test]/message: defined 'message' as 'hello puppet' |
11 | Notice: Finished catalog run in 0.03 seconds |
cron
管理cron任务
- ensure:present,absent
- command:要运行的job
- hour:
- minute:
- month:
- monthday:
- weekday:
- name:namevar
- user:运行的用户
- environment:运行时的环境变量
example:
1 | ~]# cat cron.pp |
2 | cron {'test': |
3 | name => "sync time", |
4 | command => "ntpdate 10.0.0.1 &> /dev/null", |
5 | ensure => present |
6 | } |
7 | ~]# puppet apply -v cron.pp |
8 | Notice: Compiled catalog for init.localdomain in environment production in 0.07 seconds |
9 | Info: Applying configuration version '1505055436' |
10 | Notice: /Stage[main]/Main/Cron[test]/ensure: created |
11 | Notice: Finished catalog run in 0.04 seconds |
12 | ~]# crontab -l |
13 | # HEADER: This file was autogenerated at 2017-09-10 10:57:16 -0400 by puppet. |
14 | # HEADER: While it can still be managed manually, it is definitely not recommended. |
15 | # HEADER: Note particularly that the comments starting with 'Puppet Name' should |
16 | # HEADER: not be deleted, as doing so could cause duplicate cron jobs. |
17 | # Puppet Name: sync time |
18 | * * * * * ntpdate 10.0.0.1 &> /dev/null |
package
管理安装包
- ensure: installed,latest,VERSION(2.3-1.l7),present,absent
- name: 程序包名称
- source:包来源,可以本地文件或者url
1 | ~]# cat package.pp |
2 | package {'test': |
3 | name => 'nginx', |
4 | ensure => present |
5 | } |
6 | ~]# puppet apply -v package.pp |
7 | Notice: Compiled catalog for init.localdomain in environment production in 0.44 seconds |
8 | Info: Applying configuration version '1505055747' |
9 | Notice: /Stage[main]/Main/Package[test]/ensure: created |
10 | Notice: Finished catalog run in 36.14 seconds |
11 | ~]# rpm -qa nginx |
12 | nginx-1.10.2-1.el7.x86_64 |
service
管理服务
- enable:是否开机自动启动,true|false
- ensure:启动(running),停止(stopped)
- hasrestart: 是否支持restart参数
- hasstatus: 是否支持status参数
- name: 服务名称,NameVar
- path: 服务查找路径
- pattern:用于搜索此服务相关的进程的模式;当脚本不支持restart/status时,用于确定服务是否支持处于运行状态
- restart:自定义脚本
- status:自定义脚本
- stop:自定义脚本
example:
1 | ~]# service.pp |
2 | service {'test': |
3 | name => "nginx", |
4 | ensure => running, |
5 | hasstatus => true, |
6 | hasrestart => true, |
7 | restart => "systemctl reload nginx", |
8 | path => ['/usr/bin','/usr/sbin'] |
9 | } |
10 | ~]# puppet apply -v service.pp |
11 | Notice: Compiled catalog for init.localdomain in environment production in 0.19 seconds |
12 | Info: Applying configuration version '1505056135' |
13 | Notice: /Stage[main]/Main/Service[test]/ensure: ensure changed 'stopped' to 'running' |
14 | Info: /Stage[main]/Main/Service[test]: Unscheduling refresh on Service[test] |
15 | Notice: Finished catalog run in 0.12 seconds |
16 | ~]# ps aux | grep nginx |
17 | root 31446 0.0 0.1 122240 2228 ? Ss 11:08 0:00 nginx: master process /usr/sbin/nginx |
18 | nginx 31447 0.0 0.1 122672 3296 ? S 11:08 0:00 nginx: worker process |
19 | nginx 31448 0.0 0.1 122672 3088 ? S 11:08 0:00 nginx: worker process |
20 | root 31460 0.0 0.0 112644 952 pts/0 S+ 11:09 0:00 grep --color=auto nginx |