|
1 概述
资源是puppet最基本的元素,每个资源的定义都具有标题、类型以及一系列的属性。puppet的特性就是处理资源与资源之间的依赖关系。任何相同类型的资源都会具有一些相同的属性。
资源定义有如下的特性:
a.puppet使用title在编译时期区分每个资源,使用命名变量(namevar)在执行时区分资源。
b.在同一类资源中title和namevar都是唯一的。
c.每个类型都有部分属性有默认值
d.如果不指定namevar,则默认赋予其title的值。
在puppet 3.6.2版本中,通过命令puppet describe --list可以查看到目前有49种资源类型,本文将结合例子介绍puppet的8种核心资源类型,如下
group: 组
user:用户
packge:程序包
service:服务
file:文件
exec:执行自定义命令,要求幂等
cron:周期性任务计划
notify:通知
其他类型的解释见如下的文档
https://docs.puppet.com/puppet/5.2/cheatsheet_core_types.html#notify
2 八大核心资源
group:管理组
属性:
name:组名;
gid:GID;
system:是否为系统组,true OR false;
ensure:目标状态,present/absent;
members:成员用户;
例子,定义资源清单,最后一个逗号可以写也可以省略
vim group.pp
group{'mygrp':
ensure => present,
name => mygrp66,
system => true,
}
测试资源情况
puppet apply -v --noop group.pp 如果测试通过,执行资源
puppet apply group.pp 注意:type必须使用小写字符;title是一个字符串,在同一类型中必须惟一;
user:管理用户
Manage users.
属性:
name:用户名;
uid: UID;
gid:基本组ID;
groups:附加组,不能包含基本组;
comment:注释;
expiry:过期时间 ;
home:家目录;
shell:默认shell类型;
system:是否为系统用户 ;
ensure:present/absent;
password:加密后的密码串;
例子
例子,创建一个用户,同时指定多个附加组,用列表实现,这里假设组testgrp不存在,执行会报错,所以可以定义依赖关系,用require来定义依赖关系,这里引用的是资源,所以对应的资源要存在,假设sunnygrp组已经存在,但是还是要定义mygrp这个资源
vim user.pp
group{'testgrp':
ensure => present,
}
user{'myuser':
ensure => present,
name => 'sunny66',
uid => 3333,
shell => '/sbin/nologin',
groups => [sunnygrp,testgrp],
require => [Group['sunnygrp'],Group['testgrp']],
}
group{'sunnygrp':
ensure => present,
system => true,
name => 'sunnygrp',
}
关系元参数:before/require
A before B: B依赖于A,定义在A资源中;
{
...
before => Type['B'],
...
}
B require A: B依赖于A,定义在B资源中;
{
...
require => Type['A'],
...
}
例子
依赖关系的第二种定义方法
vim user.pp
group{'testgrp1':
ensure => present,
before => User['myuser1'],
}
user{'myuser1':
ensure => present,
name => 'sunny666',
uid => 2222,
shell => '/sbin/nologin',
groups => [sunnygrp1,testgrp1],
}
group{'sunnygrp1':
ensure => present,
system => true,
name => 'sunnygrp1',
before => User['myuser1'],
}
package:管理程序包
属性:
ensure:installed, present, latest, absent, any version string (implies present)
name:包名;注意,如果不指定name,name这个名字默认就是title的名称
source:程序包来源,仅对不会自动下载相关程序包的provider有用,例如rpm或dpkg;不同操作系统的安装方法,一般不需要指定,因为会自动安装
例子,安装redis包
package{'redis':
ensure => latest,
}
service:管理运行服务
属性:
ensure:服务是否应该运行。 有效值为“stopped”(也称为“false”),“runnig”(也称为“true”)。
enable:是否应开机启用服务。 有效值为“true”,“false”,“manual”。
name:启动的服务名称
path:用于查找init脚本的搜索路径。 多个值应该用冒号分隔或作为数组提供..脚本的搜索路径,默认path为/etc/init.d/;
hasrestart:是否支持启动功能,如果是true,则直接restart,如果如false,就执行stop后执行start来重启,默认false
hasstatus:默认true
start:手动定义启动命令;
stop:停止服务
status:服务状态
restart:手动指定*restart*命令。 如果未指定,服务将被停止,然后启动。 通常用于定义reload操作;
binary:启动服务,启动程序的路径
path:启动服务脚本路径
例子
启动redis,有依赖关系,假设卸掉redis,但是测试还是正常,真正执行的时候却失败了,因此启动服务脚本中定义资源package
vim service.pp
service{'redis':
ensure => running,
enable => true,
hasrestart => true,
restart => 'systemctl restart redis',
require => Package['redis'],
}
package{'redis':
ensure => latest,
}
file:管理文件
管理文件其内容,所有权和权限。
ensure:文件是否应该存在,如果是,应该是什么类型的文件。 可能的值是“present”,“absent”,“file”,“directory”和“link”。
file:类型为普通文件,其内容由content属性生成或复制由source属性指向的文件路径来创建;
link:类型为符号链接文件,必须由target属性指明其链接的目标文件;
directory:类型为目录,可通过source指向的路径复制生成,recurse属性指明是否递归复制;
path:文件路径;
source:源文件;
content:文件内容;
target:符号链接的目标文件;
owner:属主
group:属组
mode:权限;
atime/ctime/mtime:时间戳;
例子
复制文件,先复制一份redis配置文件,并进行修改,然后通过puppet的file进行复制到对应主机
cp /etc/redis.conf /root、
vim file.pp
file{'/etc/redis.conf':
ensure => file,
source => '/root/redis.conf',
owner => 'redis',
group => 'root',
mode => '0644',
}
例子
复制目录,注意,以下recurse对应的true是布尔值,不能加引号
vim file.pp
file{'yumfile':
ensure => directory,
path => '/tmp/yum.repos.d/',
source => '/etc/yum.repos.d/',
recurse => true,
}
复制文件到目录下,那么ensure为directory配置就不会生效,直接复制为一个文件,而不生成目录,即如下的例子中,只会在/tmp下生成一个名为test的文件,内容是/etc/issue的内容,而不会在/tmp/test这个目录下生成issue这个文件
file{'test':
ensure => directory,
path => '/tmp/test',
source => '/etc/issue',
}
如果有多个源文件,那么只会复制一个文件,如下例子,只会复制/etc/issue这个文件,新生成的文件名为/tmp/test
file{'test':
ensure => directory,
path => '/tmp/test',
source => ['/etc/issue','/etc/group'],
}
例子
创建链接
file{'redis.conf':
ensure => link,
path => '/tmp/redis.conf',
target => '/etc/redis.conf',
}
通知元参数:订阅或者通知关系
A notify B:B依赖于A,接受由A触发refresh;
B subscribe A:B依赖于A,接受由A触发refresh;B监控A资源的内容变化,一定A变化,B要跟着发送对应变化
在一资源中,notify和suscribe只需要二者选一个即可
通知关系:通知相关的其它资源进行“刷新”操作;
notify
A notify B:B依赖于A,且A发生改变后会通知B;
{
...
notify => Type['B'],
...
}
subscribe
B subscribe A:B依赖于A,且B监控A资源的变化产生的事件;
{
...
subscribe => Type['A'],
...
}
例子:
安装redis,并启动redis服务,当redis的配置文件更改时,重启服务,用通知链表示表示依赖关系
vim service.pp
service{'redis':
ensure => running,
enable => true,
hasrestart => true,
restart => 'systemctl restart redis',
subscribe => File['redis.conf'],
}
package{'redis':
ensure => latest,
}
file{'redis.conf':
path => '/etc/redis.conf',
source => '/root/redis.conf',
ensure => file,
mode => '0644',
owner => redis,
group => root,
# notify => Service['redis'],
}
Package['redis'] -> File['redis.conf'] ~> Service['redis']
以上例子,可以改成如下,->表示package先于file,~>表示file先于service,同时service订阅了file
#service with notify or subscribe
package{'redis':
ensure => latest,
} ->
file{'redis.conf':
path => '/etc/redis.conf',
source => '/root/redis.conf',
ensure => file,
mode => '0644',
owner => redis,
group => root,
} ~>
service{'redis':
ensure => running,
enable => true,
hasrestart => true,
restart => 'systemctl restart redis',
}
依赖关系:当某个条件执行后,才会执行
before
require
例子:
以下例子,File['test.symlink']依赖于File['test.txt'],只有当File['test.txt']资源执行,File['test.symlink']才会被执行
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.txt']执行后才会执行File['test.symlink']
file{'test.txt':
path => '/tmp/test.txt',
ensure => file,
source => '/etc/fstab',
before => File['test.symlink'],
}
file{'test.symlink':
path => '/tmp/test.sysmlink',
target => '/tmp/test.txt',
ensure => link,
}
exec:执行外部命令
exec资源中的任何命令必须能够运行多次而不会造成危害,即它必须是幂等的。
**command** (*namevar*):要运行的命令;
cwd:运行该命令的目录。
creates:文件路径,仅此路径表示的文件不存在时,command方才执行;
user/group:运行命令的用户身份;
path:用于命令执行的搜索路径。 如果没有指定路径,则命令必须是绝对路径。
onlyif:此属性指定一个命令,此命令正常(退出码为0)运行时,当前command才会运行;
unless:此属性指定一个命令,此命令非正常(退出码为非0)运行时,当前command才会运行;
refresh:重新执行当前command的替代命令;
refreshonly:仅接收到订阅的资源的通知时方才运行;
例子:
创建目录
mkdir不幂等,因此定义creates,只有/tmp/hi.dir/不存在时才执行command
vim exec.pp
exec{'makedir':
command => 'mkdir /tmp/hi.dir',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin',
creates => '/tmp/hi.dir',
}
创建用户
其中,unless表示只有id sunny88失败,那么command命令才会执行,如果id sunny88成功了,那么command命令就不会执行,即只有sunny88用户不存在的时候才会执行command命令
exec{'createuser':
command => 'useradd sunny88',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin',
unless => 'id sunny88',
}
安装包
安装tree服务包,只有查找到sunny仓库时才会执行command
exec{'installpkg':
command => 'yum -y install tree',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin',
onlyif => 'yum repolist | grep -i sunny',
}
newaliases是一个命令,只有当/etc/aliases文件发送变化后才会执行newaliases
file{'/etc/aliases':
path => '/etc/aliases',
ensure => file,
before => Exec['newaliases'],
}
exec{'newaliases':
path => ["/usr/local/sbin","/usr/local/bin","/usr/local","/usr/bin"],
subscribe => File["/etc/aliases"],
refreshonly => true,
}
例子
为redis服务器生成配置文件,当模板配置文件改变时,通知exec['backupfile'],并且将本次变化后的配置文件备份到指定路径下,这里有个问题是,第一次的配置文件将不会被备份,因此要手动备份第一次的配置文件
注意,以下的cp命令不幂等,因此复制的时候,建议将备份的文件新增名字后加上时间为后缀。为redis.conf-$(date +%F-%H-%M-%S),防止冲突
file{'/etc/redis.conf':
source => '/root/redis.conf',
ensure => file,
}
exec{'mkdir':
command => 'mkdir /backups',
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin',
unless => 'ls /backups',
before => Exec['backupfile'],
}
exec{'backupfile':
command => "cp /etc/redis.conf /backups/redis.conf-$(date +%F-%H-%M-%S)",
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin',
refreshonly => true,
subscribe => File['/etc/redis.conf'],
}
cron:安装和管理cron作业
每个由Puppet创建的cron资源都需要一个命令和至少一个周期性属性(小时,分钟,月份,月份,工作日或特殊)。
command:要执行的任务;
ensure:present/absent;
hour:
minute:
monthday:
month:
weekday:
user:以哪个用户的身份运行命令
target:添加为哪个用户的任务
name:cron job的名称;
示例:每隔三分钟执行一次计划任务
cron{'timesync':
command => '/usr/sbin/ntpdate 172.18.50.61 &> /dev/null',
ensure => present,
minute => '*/3',
user => 'root',
}
notify:发送消息
将任意消息发送到代理运行时日志。
属性:
message:信息内容
name:信息名称;
例子
发出通知消息
notify{'hello':
message => 'hello everyone,I am sunny',
name => 'Say hello',
}
到这里,8大核心资源的定义和使用介绍完成。 |
|