侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

puppet的详细使用

zze
zze
2020-05-24 / 0 评论 / 0 点赞 / 579 阅读 / 50234 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

介绍

puppet 是 C/S 架构的,有服务端,也有客户端,管理员可以通过 puppet 服务端(master),管理每一台被管理的服务器,但是需要 puppet 客户端作为中介,也就是说,puppet 客户端作为代理(agent),接收来自 puppet服务端的配置信息,按照服务端(master)发送过来的配置信息,对被管理服务器进行配置。当客户端按照配置信息执行完成相关配置以后,会将执行信息发送到服务端,比如执行成功与否,执行结果等。

默认情况下,每 30 分钟 puppet 客户端会向 puppet 服务端发起一次请求,请求受管理服务器的配置信息, puppet 服务端将配置信息发送给客户端,客户端根据反回的信息进行判断,判断被管理服务器是否符合管理员定义的配置,puppet 的这种工作模式就是 C/S 架构的,也可以理解为 master/agent 的工作模式。

后续简称 puppet 服务端为 master,客户端为 agent。

不是一定要等 30 分钟,可手动通过 master 推送更新到 agent。

相关术语

  • 资源:要操作的对象就是资源;
  • Manifest:也被称为清单,就是我们定义的配置文件,告诉 agent 需要执行什么操作;
  • Catalog:Manifest 被“翻译”后才能被 puppet 所执行,“翻译”后的文件称为 Catalog;
  • 资源抽象层:资源抽象层会自动识别操作资源所在的平台(OS),并按照平台特性做出特定的操作;
  • Provider:提供者,在特定的平台资源抽象层需要选择特定的 Provider 进行操作,比如要使用 puppet 做一个安装软件的操作,此时 yum 就为 CentOS 的提供者,apt 为 Ubuntu 的提供者;

agent 所接收到的就是被翻译后的文件,即 Catalog。

使用

安装

以 CentOS 7 为例,如果操作主机是 agent,则需要安装客户端:

$ yum -y install puppet

如果操作主机时 master,则需要同时安装服务端和客户端:

$ yum -y install puppet puppet-server

需要添加 epel 源。

安装完成后可通过 puppet help 查看使用帮助,其基本使用语法如下:

puppet <subcommand> [options] <action> [options]
	subcommand:表示子命令;
	options:表示选项,也就是说,使用 puppet 子命令时可以跟随相应的选项;
	action:表示动作,我们也可以把 action 理解为子命令的子命令;
	options:action 后面的 options 表示 action 对应的选项,我们也可以理解成子命令的子命令对应的选项;

查看子命令的用法:
	puppet help <subcommand>
	puppet man <subcommand>

查看 action 的用法:
	puppet help <subcommand> <action>

编写清单

puppet 虽然是 master/client 架构的,但是学习期间为简便操作,我们可以在单机编写配置文件,并且手动通过 puppet 命令来编译并执行清单文件。

清单可以看作是由多个资源组成的一个配置文件,要操作什么资源,就将对应资源写入清单即可,清单的后缀名为 .pp

资源在清单中的定义格式如下:

resourceType {'title':
        attribute1 => value1,
        attribute2 => value2,
        ...
        attributeN => valueN,
}

可使用 # 注释行。

下面对上述格式做一下说明:

  • resourceType:资源类型;
  • title:标题,也是资源标识,同类型资源的标题不能重复;
  • attributeN & valueN:属性与属性对应的值;

常用资源类型有如下:

资源名描述
file文件或目录
package程序包
service服务
user用户
group
cron定时任务
Exec命令
yumrepoYum 仓库

可通过 puppet describe -l 查看所有的资源类型,还可通过 puppet [-s] [-m] describe <type> 查看某类型资源的详细信息,-s 指定以简短格式输出,[-m] 指定查看元数据信息,详细信息内容包括指定资源支持的属性以及 Provider 等信息。

特殊属性:

  • 名称变量,大多数(并不是所有)资源的名称变量可通过 name 属性设定,当名称变量省略时名称变量的值默认为 title 值;
  • ensure 属性,用来定义资源的目标状态,不同的资源中 ensure 的值可能不同,如 user 资源的 ensure 可以为 present 表示用户必须存在,也可以为 absent 表示用户必须缺席,而 service 资源的 ensure 值往往被设定为 stoppedrunning,分别表示停止或运行状态;
  • 元属性,可用来定义资源的元信息,常用到的元属性有 beforerequirenotifysubscribe

以在当前服务器上创建一个名为 zze 的用户为例,我这里编写名为 test.pp 的清单文件内容如下:

# 资源类型为 user, 标题为 zze
user {'zze':
        # name 属性指定要创建的用户名
        name => zze,
        # ensure 属性指定目标状态, present 则表示如果存在对应用户则不执行, 不存在则创建
        ensure => present,
}

模拟执行该清单:

# apply:执行操作
# --verbose:显示详细信息
# --noop:模拟执行,并不会真正执行
$ puppet apply --verbose --noop test.pp 
Notice: Compiled catalog for centos7-204 in environment production in 0.08 seconds
Info: Applying configuration version '1589637228'
# current_value absent 说明当前操作还未达到目标状态,所以真正执行此操作时会创建用户
Notice: /Stage[main]/Main/User[create user zze]/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.03 seconds

真正执行:

# 执行
$ puppet apply --verbose test.pp 
Notice: Compiled catalog for centos7-204 in environment production in 0.08 seconds
Info: Applying configuration version '1589637500'
# 提示已创建
Notice: /Stage[main]/Main/User[create user zze]/ensure: created
Notice: Finished catalog run in 0.05 seconds
# 检查是否创建成功
$ id zze
uid=1000(zze) gid=1000(zze) groups=1000(zze)

资源类型

下面列出常用的资源类型。

user

user 资源的作用是用来管理目标主机上的用户,比如创建、修改、删除用户等,其常用属性如下:

属性名 描述
name表示对应用户的用户名称,可省。
ensure确定用户的目标状态,通常将其值设置为 presentabsent,分别表示用户必须存在或用户必须不能存在,当然,如果我们将 ensure 值指定为 absent 以后,就没有必要在指定其他属性了,一般 ensurepresent 时,配置其他属性值,如果 ensure 的值为 present,但是当前用户已经存在,此时,puppet 会判断已经存在的用户与我们定义的用户资源的其他属性是否一致,如果不一致,puppet 则会做出对应操作,使目标服务器上已经存在的用户与我们定义的资源的属性保持一致,所以,absent 可以理解为删除用户,present 在不同的场景中,可以理解为创建用户或者修改用户,或者这样理解,present 的作用就是保证用户必须存在,并且与我们定义的资源的状态完全一致,其他资源的此属性也都类似。
uid指定用户的 uid
groups指定用户的附属组,可以同时指定多个附属组,同理,对应附属组必须事先存在,而且需要注意,此属性中不能包含用户的基本组,也就是说不能包含 gid 对应的组名,指定附属组时,必须使用组名指定,不能使用对应组的 gid,附属组可以指定多个值,当属性可以指定多个值时,可以使用 [] 将多个属性值括起,每个属性值之间同样需要逗号隔开,我们可以把 [] 理解成列表。
home指定用户的家目录,使用此属性时需要注意,虽然 puppet 在创建用户或者修改用户时会按照 home 属性的值指定用户的家目录,但是对应的家目录 puppet 不会为我们自动创建,在没有使用 home 属性的情况下 puppet 为我们创建用户时,不会创建对应的家目录,如果想要 puppet 能在创建用户时为我们自动创建用户的家目录,并且将对应的配置文件填充到用户家目录中,需要使用 managehome 属性。
managehome表示 puppet 是否管理用户的家目录,在创建用户时,如果不添加此属性,用户对应的家目录不会被创建,可能会造成用户登录后没有家目录或者 shell 不可用的情况。
shell指定用户的默认登录 shell 类型。
password指定用户的密码,注意,这个密码是使用单向加密算法加密过的密码,不是明文密码,如果你的密码使用 md5 的方式加密,可以使用 grub-md5-crypt 命令生成加密后的密码,如果你的密码使用 sha256 的方式加密,可以使用类似如下命令生成:perl -e 'print crypt("password", q($6$salt$)), "\n";'
comment使用此属性设置用户的描述信息。
system是否指定用户为系统用户,当显示指定 system 属性并且设置为 true 时,则为系统用户。

group

group资源的作用就是用来管理目标服务器上的组的,group 资源的常用属性如下:

属性名 描述
name表示组对应的名称,可省。
ensure确定组的目标状态,通常将其值设置为 presentabsentabsent 表示组必须不能存在,可以理解为删除组,present 表示组必须存在,并且目标状态与我们定义的相同,如果不同,puppet 会执行对应动作,直到最终一致。
gid组ID号
system指定当前组是否为系统组,默认为 false,当显示指定 system 属性并且设置为 true 时,则为系统组。

cron

cron 资源的作用就是管理目标服务器上的定时任务的,作用相当于 crontab 命令,cron 资源的常用属性如下:

属性名 描述
name表示组对应 crontab 任务的名称,可省。
ensure表示创建或删除定时任务,可省,省略 ensure 时,默认值为 present,通常将其值设置为 presentabsentpresent 表示对应定时任务必须存在且与定义状态完全一致,absent 表示对应定时任务不能存在。
command指定定时任务需要执行的命令。
user指定当前定时任务是为哪个用户设定的。
minute指定定时任务的分钟时间格式,上图示例中,/1 表示每 1 分钟,省略不写默认为 *
hour指定定时任务的小时时间格式,省略不写默认为 *
monthday指定定时任务的日时间格式,省略不写默认为 *
month指定定时任务的月时间格式,省略不写默认为 *
weekday指定定时任务的星期时间格式,省略不写默认为 *

package

package 资源的作用就是管理目标服务器上的程序包,package 资源的常用属性如下:

属性名 描述
name表示对应安装包的名称,可省,省略后与资源 title 值相同,但是需要注意:不同系统平台或者不同的系统发行版中,同一个软件的名称可能不同,比如,CentOS 中,apache 的 http server 被称为 Httpd,而在 Ubuntu 中,apache 的 http server 被称为 Apache2 ,所以,如果不同的被管理服务器中需要的安装包的名称不同,我们往往需要判断操作系统版本,然后给出不同的 package 名称。
ensureensure 的值对于 package 资源来说,相对丰富一点,可以使用 absentpresentinstalledlatest, 其中,absent 表示卸载,presentinstalled 都表示安装,没有什么区别,latest 表示安装能够获取到的最新的版本。
ource指定安装包文件,如果被管理服务器上存在类似 yum 源这样的提供者,则可以省略此属性,省略此属性后,yum 源会按照 name 属性或 title 的名称自动安装对应的 package,如果对应被管理服务器上没有类似 yum 源这样的提供者,或者说,当被管理服务器上没有能够支持自动下载安装软件的提供者时,那么 source 属性则是必须的,比如使用 rpm 包安装对应软件,那么我们则必须通过 source 属性指明 rpm 包的路径,同时需要注意,对于 package 资源来说,puppet 默认使用 yum 作为 Redhat/CentOS 系统的提供者,所以,在使用 source 属性指定 rpm 包的同时,还需要使用 provider 属性,指定使用 rpm 作为本次操作的提供者。
provider当 puppet 默认的 provider 不符合我们的实际使用场景时,可以指定使用哪种 provider,通常在一个操作系统下有多个提供者的情况下,可以使用此属性指明使用哪个提供者。

service

service 资源的作用就是启动或停止目标服务器上的服务,service 资源的常用属性如下:

属性名 描述
enable此属性用于设置对应服务是否开机自动启动服务,此属性设置为 true 表示开机自动启动服务,false 表示不会开机自启。
ensure表示对应服务的当前状态,不要与 enable 搞混了,enable 属性是设置服务是否开机自启的,而 ensure 是设置当前服务是否处于启动状态,对于 service 资源来说,ensure 属性的值可以设置为 runningtrue,表示启动对应服务,也可以设置为 stoppedfalse,表示停止对应服务。
hasrestart表示标明当前服务是否支持 restart 命令,设置为 true 表示支持 restartfalse表示不支持 restart,如果不支持 restart 命令,那么要重启服务时,则会先 stop 服务,再 start 服务。
hasstatus表示标明当前服务是否支持 status 命令。
path服务对应的 init 脚本文件的路径,对于 CentOS 来说,默认路径为 /etc/rc.d/init.d,当然,CentOS 7 则无需此属性,因为 CentOS 7 中使用 unit,而不再使用脚本。
start用户手动指定服务对应的启动命令。
restart用户手动指定的 restart 操作对应的命令,但是为了保险起见,通常会将此属性对应的命令设置为 reload,而非 restart

file

file 资源的功能比较丰富,它可以用来管理文件的内容、属主属组以及文件的权限,同时可以用它管理目录、链接文件,file 资源的常用属性如下:

属性名 描述
path通过此属性指定 file 资源所在路径,还记得其它资源中的 name 属性吗,在其他资源中,name 属性往往是可省的,因为 name 属性是大多数资源的"名称变量"(namevar),其他资源中,name 属性省略后,资源的名称与资源的 title 相同,而在 file 资源中,path 属性才是 file 资源的"名称变量"(namevar),当我们省略 path 属性时,path 属性对应的值与 file 资源的 title 相同,所以,如果省略 path 属性,file 资源的 title 则必须为文件的路径,当然,如果不想将 file 资源的 title 设置为 file 的路径,则不能省略 path 属性。
ensurefile 资源可以管理文件、目录、软连接,那么,当前 file 资源到底是用来管理文件的呢,还是管理目录的呢,我们可以使用 ensure 属性,定义当前 file 资源的类型,ensure 的值可以为 presentabsentfiledirectorylink,当 ensure 的值为 file 时,file 资源代表一个文件,当 ensure 的值为 directory 时,file 资源代表一个目录,当 ensure 的值为 link 时,file 资源代表一个软连接,当 ensure 的值为 absent 时,表示要删除对应的资源,当 ensure 的值为 present 时,与 ensure 的值为 file 时相同。
contentensure 属性的值为 file 时,使用此属性可以指定文件的内容,将要写入文件的内容使用引号引起即可,也可以将指定内容替换为变量的值,注意,此属性与将要提到的 source 属性不能同时存在于同一个资源中。
sourceensure 属性的值为 file 时,使用此属性可以指定当前文件的内容从哪个文件中获取,可以理解为把某个文件的内容覆盖到当前文件,或者理解为复制文件也是可以的,使用 source 属性,还可以通过指定的 puppet url 远程复制文件,但是这是后话,实际应用时再演示,source 属性与 content 属性本质上都是设置文件内容的,它们不能同时存在于同一个资源中。当 ensure 属性的值为 directory 时,使用 source 属性指定另一个目录,则表示复制另一个目录,但是需要注意,当 ensuredirectory 时,使用 source 属性的同时,需要配合 recurse 属性,否则被复制目录中的子目录或者文件将不会被同时复制过来。
recurse此属性用于设置被操作源目录是否被递归,当 ensure 属性的值为 directory 时,同时 source 属性对应的值为一个目录,那么需要将 recurse 属性设置为 true,被复制目录中的子目录和文件才能被复制到当前目录中,注意,recurse 属性只有在配合 source 属性时才会递归的复制目录,如果 ensure 属性设置为 directory,但是没有配合 source 属性,即使将 recurse 属性设置为 true,puppet 仍然不会执行递归操作。
forceensure 属性的值为 absent 时,同时 file 资源对应的 path 或者 title 为一个目录(非文件),那么则必须将 force 属性设置为 true,才能删除对应的目录以及目录下的文件,当 ensure 的值为 absent,但是 file 资源对应的 path 或者 title 为一个文件,那么则不需要设置 force 属性,即可正常的删除。
targetensure 属性的值为 link 时,我们通过 target 属性指定连接文件的目标文件。
owner指定 file 资源对应的属主。
group指定 file 资源对应的属组。
mode指定 file 资源对应的权限。
Backup使用此属性结合 filebucket 资源可以实现文件备份,同样,在后面的实际应用中,我们再做具体解释。

exec

通过 exec 资源,可以在被管理服务器上执行对应的命令,exec 资源的常用属性如下:

属性名 描述
path此属性的功能类似 PATH 环境变量,也就是说,我们可以指定,从哪些目录中搜索将要执行的命令,如果有多个目录,可以使用冒号 : 隔开(注意,是冒号,不是分号,就跟 PATH 环境变量的设置方法相同),除了使用 : 隔开表示多个路径,还能使用列表的方式表示多个 path 路径,如果不使用 path 属性,当我们指定命令时,需要给出命令所在位置的绝对路径。
command此属性用于指定将要执行的命令,如果 path 属性已经指定对应命令所在目录,那么此属性直接使用命令名称即可,如果未使用 path 属性,那么 command 属性则必须给出绝对路径。
cwd表示在何处运行对应的 command,也就是执行命令的目录。
user以哪个用户的身份运行对应命令。
group以哪个组的身份运行对应的命令。
onlyif此属性表示“运行条件”,当 onlyif 属性对应的命令执行成功时,才会执行 command 属性对应的命令,换句话说,就是当 onlyif 属性对应的命令执行的返回值为0 时,才会执行 command 属性对应的命令。
refreshonly仅接收到订阅资源的通知时,才执行对应的命令,一般与 subscribe 配合,此属性值可以设置为 true 或者 false,这个属性牵扯到 puppet 调用资源的顺序,我们在总结资源的依赖关系时,大家自然就会明白,现在不明白可以跳过此属性。

yumrepo

yumrepo 资源的作用就是在被管理服务器上设置对应的 yum 源,常用属性如下:

属性名描述
name可省,表示 yum 文件的名称与 yum 源的名称相同。
baseurl设置 yum 源的 url,与 yum 的配置没有任何区别。
gpgcheck是否开启 gpg 检查,设置为 0 表示不检查。
gpgkey当启动 gpgcheck 时对应的 key。
enabled是否启动这个 yum 源 1 表示启动,0 为不启动。

依赖与通知

元属性

当我们在一个清单中配置多个资源时,这些资源之间往往存在着依赖关系,比如,当我们想要在服务器上安装 nginx 并且想要在 nginx 安装完成后启动 nginx 服务,那么我们将会使用到两个资源, package 资源与 service 资源,而且 package 资源应该在 service 资源之前被执行,因为如果想要启动 nginx 那么则必须先安装了 nginx 才行,即 service 资源依赖package 资源。

同样,当我们修改了 nginx 的配置文件时,对应 nginx 服务的配置应该被重载,换句话说就是,当“配置文件被修改”时,nginx 服务应该被通知去重载配置文件了。

所以,当多个资源之间存在这种依赖关系或者通知关系的时候,则需要管理员在清单中定义。具体的定义则需要用到之前提到的元属性了,那几个元属性可分为如下两组:

  • before/require:这两个元属性可定义资源之间的依赖关系;
  • notify/subscribe:这两个元属性可定义资源之间的通知关系;

依赖

我们可以通过 before/require 这两个元属性定义资源之间的依赖关系。

以创建一个名为 zze 组 id 为 666 的用户为例,首先肯定必须存在组 id 为 666 的这个组之后 zze 用户才能被创建成功,即 zze 用户的创建依赖于组 id 为 666 的组,该例在清单中的定义方式如下:

user {'zze':
        ensure => present,
        gid => 666,
        managehome => true,
        require => Group['nbgroup']
}

group {'nbgroup':
        ensure => present,
        gid => 666
}

即在名为 zzeuser 资源中使用 require 属性标识了它依赖于名为 nbgroupgroup 资源执行。

也可使用 before 属性完成上述相同的功能,修改清单内容如下:

user {'zze':
        ensure => present,
        gid => 666,
        managehome => true,
}

group {'nbgroup':
        ensure => present,
        gid => 666,
        before => User['zze']
}

即在名为 nbgroupgroup 资源中使用 before 属性标识了它必须在名为 zzeuser 资源之前执行。

不管是使用 require 还是 before,其值格式都为 ResourceType[title]ResourceType 的首字母必须大写。

通知

我们可以通过 notify/subscribe 定义资源之间的通知关系。

比如,修改 nginx 配置文件后,需要通知 nginx 进行重载操作,此种情况的资源在清单中定义如下:

file {'nginx_conf':
        path => '/etc/nginx/nginx.conf',
        ensure => present,
        source => '/template/default.conf'
}

exec {"nginx_reload":
        command => '/usr/sbin/nginx -s reload',
        subscribe => File['nginx_conf'],
        refreshonly => true
}

即在名为 nginx_reloadexec 资源中通过 subscribe 属性订阅了名为 nginx_conf 的资源,当该资源发生变化时 nginx_reload 资源就会被触发从而执行 nginx 的重载操作。

exec 资源的 refreshonly 表示只有在订阅的资源发生变化时才执行 command 指定的命令。

也可以通过 notify 完成上述相同的功能,修改清单内容如下:

file {'nginx_conf':
        path => '/etc/nginx/nginx.conf',
        ensure => present,
        source => '/template/default.conf',
        notify => Exec['nginx_conf'],
}

exec {"nginx_reload":
        command => '/usr/sbin/nginx -s reload',
        refreshonly => true
}

即在名为 nginx_conffile 资源中通过 notify 属性指定当 sourcepath 指定的文件发生变化时,就通知名为 nginx_reloadexec 资源执行。

因为 exec 资源的 refreshonly 属性的值为 true,所以,只有在接收到 nginx_conf 的通知时才会执行。

关系链

除了通过元属性来定义资源的依赖和通知关系外,还可通过“关系链”的方式来完成同样的功能。

以上述「依赖」中的例子为例,可使用如下方式来达到同 require/before 的相同效果,如下:

user {'zze':
        ensure => present,
        gid => 666,
        managehome => true,
}

group {'nbgroup':
        ensure => present,
        gid => 666
}

Group['nbgroup'] -> User['zze']

即可以通过 -> 来创建一个执行次序链,前面的定义的资源先执行,后面定义的资源后执行。


以上述「通知」中的例子为例,可使用如下方式达到同 notify/subscribe 的相同效果,如下:

file {'nginx_conf':
        path => '/etc/nginx/nginx.conf',
        ensure => present,
        source => '/template/default.conf'
}

exec {"nginx_reload":
        command => '/usr/sbin/nginx -s reload',
        refreshonly => true
}

File['nginx_conf'] ~> Exec['nginx_reload']

即可以通过 ~> 来创建一个执行次序链,前面的定义的资源的发生变化会触发后面的资源执行。

变量

特点

puppet 变量具有以下特点:

  • puppet 的变量名称须以 $ 开头,赋值操作符为 =
  • 任何正常数据类型(非正则)的值都可以赋予 puppet 中的变量,如字符串、数值、布尔值、数组、hash 以及特殊的 undef 值(即变量未被赋值);
  • puppet 的每个变量都有两个名字:简短名称和长格式完全限定名称(FQN),完全限定名称的格式为 $scope::variable
  • scope 是一个特定的代码区域,用于同程序中的其它代码隔离开来;
    在 puppet 中,scope 可用于限定变量及资源默认属性的作用范围,但不能用于限定资源名称及资源引用的生效范围;

数据类型

puppet 语言支持多种数据类型以用于变量和属性的值,以及函数的参数;

字符型:

  • 非结构化的文本字符串,可以使用引号,也可以不用;
  • 单引号中的变量不会替换,而双引号中的能够进行变量替换;
  • 字符型值也支持使用转义符;

数值型:

  • 可为整数或浮点数,不过,puppet 只有在数值上下文才把数值当数值型对待,其它情况下一律以字符型处理;

数组:

  • 数组值为中括号 [] 中的以逗号分隔的项目列表,最后一个项目后面可以有逗号;
  • 数组中的元素可以为任意可用数据类型,包括 hash 或其它数组;
  • 数组索引为从 0 开始的整数,也可以使用负数索引;

布尔型:

  • truefalse,不能加引号;
  • if 语句的测试条件和比较表达式都会返回布尔型值;
  • 另外,其它数据类型也可自动转换为布尔型,如空字符串为 false 等;

undef:

  • 从未被声明的变量的值类型即为 undef
  • 也可手动为某变量赋予 undef 值,即直接使用不加引号的 undef 字符
    串;

hash:

  • 即为键值数据类型,键和值之间使用 => 分隔,键值对儿定义在 {} 中,彼此间以逗号分隔;
  • 其键为字符型数据,而值可以为 puppet 支持的任意数据类型;
  • 访问 hash 类型的数据元素要使用“键”当作索引进行;

正则表达式:

  • 属于 puppet 的非标准数据类型,不能赋值给变量,仅能用于有限的几个接受正则表达式的地方,即接受使用 =~!~ 匹配操作符的位置,通常包括 case 语句中的selector,以及节点名称匹配的位置;
  • 它们不能传递给函数或用于资源属性的定义;
  • puppet 中的正则表达式支持使用 (?<ENABLED OPTION>:<SUBPAT TERN>)和(?-<DISABLED OPTION>:<SUBPATTERN>) 两个特殊的符号;

例如下面的示例表示做正则表达式匹配时启用选项 i (忽略字符大小写),但不支持使用 m (把 . 当作换行符)和 x (忽略模式中的空白字符和注释);

$packages = $operatingsystem ? {
	/(?i-mx:ubuntu|debian)/ => 'apache2',
	/(?i-mx:centos|fedora|redhat)	=> 'httpd',
}
# 其含义为:
# 	$operatingsystem 变量匹配 /(?i-mx:ubuntu|debian)/ 模式时,将 apache2 的值赋给 $packages
# 	$operatingsystem 变量匹配 /(?i-mx:centos|fedora|redhat) 模式时,将 httpd 的值赋给 $packages

种类

1、自定义变量,如 $webserver=nginx

2、facter 变量,用于保存客户机的相关信息,可直接引用,可通过 facter -p 查看;

3、内置变量,常用内置变量有如下:

客户端内置:
	$clientcert:客户端证书;
	$clientversion:客户端版本;
服务端内置:
	$servername:服务端主机名称;
	$serverip:服务端 ip;
	$serverversion:服务端版本;
	$module_version:当前使用的模块名;

条件判断

if

单分支语法:

if CONDITION {
	statement
  ...
}

双分支语法:

if CONDITION {
	statement
  ...
} else {
  statement
  ...
}

多分支语法:

if CONDITION {
	statement
  ...
} else if CONDITION {
	statement
  ...
} else {
	statement
  ...
}

例 1:输出当前的处理器信息。

$ cat test1.pp 
# $processorcount 可以取得当前主机的处理器数量
if $processorcount > 1 {
        # notice 是一个函数,类似 echo 的效果,会将传入参数输出到控制台
        notice("处理器数量大于 1")
} else {
        notice("处理器数量等于 1")
}

执行结果如下:

$ puppet apply -v test1.pp 
Notice: Scope(Class[main]): 处理器数量等于 1
Notice: Compiled catalog for centos7-200 in environment production in 0.01 seconds
Info: Applying configuration version '1590204521'
Notice: Finished catalog run in 0.02 seconds

例 2:使用正则表达式判断并输出当前系统发型版信息。

$ cat test2.pp 
# $operatingsystem 变量保存了当前系统发行版名称
if $operatingsystem =~ /^(?i-mx:(centos|redhat))/ {
        # $1 是上述正则表达式匹配到的第一个内容
        notice("Welcome to $1 linux server")
}

执行结果如下:

$ puppet apply -v test2.pp 
Notice: Scope(Class[main]): Welcome to CentOS linux server
Notice: Compiled catalog for centos7-200 in environment production in 0.01 seconds
Info: Applying configuration version '1590205140'
Notice: Finished catalog run in 0.02 seconds

case

类似 if 语句,case 语句会从多个代码块中选择一个分支执行,这跟其它编程语言中的 case 语句功能一致。
case 语句会接受一个控制表达式和一组 case 代码块,并执行第一个匹配到控制表达式的块。

语法如下:

case CONTROL_EXPRESS {
	case1,...: { statement... }
  case2,...: { statement... }
  ...
  default: { statement... }
}

例:输出当前的系统发行版信息。

$ cat test3.pp 
case $operatingsystem {
        # 完全匹配单个值
        'Solaris': { notice("Welcome to Solaris") }   
        # 完全匹配多个值
        'RedHat', 'CentOS': { notice("Welcome to RedHat OSFamily") }
        # 正则匹配
        '/^(Debian|Ubuntu)$/': {notice("Welcome to $1 linux") }
        # 上述都没匹配到则执行此代码块
        default: { notice("Welcome, alien *_*") }
}

执行结果如下:

$ puppet apply -v test3.pp 
Notice: Scope(Class[main]): Welcome to RedHat OSFamily
Notice: Compiled catalog for centos7-200 in environment production in 0.01 seconds
Info: Applying configuration version '1590205853'
Notice: Finished catalog run in 0.02 seconds

selector

selector 类似于 case,但分支的作用不在于执行代码片段,而是返回一个直接值(plain value)。

selector 只能用于期望出现直接值的地方,这包括变量赋值、资源属性、函数参数、资源标题、其它 selector 的值及表达式。

selector 不能用于一个已经嵌套于 selector 的 case 中,也不能用于一个已经嵌套于 casecase 语句中。

语法如下:

CONTROL_VARIABLE ? {
  case1 => value1
  case2 => value2
  ...
  default => valueN
}

注意点:

  • 整个 selector 语句会被当作一个 单独的值,puppet 会将控制变量按列出的次序与每个 case 进行比较,并在遇到一个匹配的 case 后,将其值作为整个语句的值进行返回,并忽略后面的其它 case

  • 控制变量与各 case 比较的方式与 case 语句相同,但如果没有任何一个 case 与控制变量匹配时,puppet 在 编译时将会返回一个错误,因此,实践中,其必须提供 default case

  • selector 的控制变量只能是变量或有返回值的函数,切记不能使用表达式;

  • 其各 case 可以是直接值(需要加引号)、变量、能调用返回值的函数、正则表达式模式或 default

  • 但与 case 语句所不同的是,selector 的各 case 不能使用列表;

  • selector 的各 case 的值可以是一个除了 hash 以外的直接值、变量、能调用返回值的函数或其它的 selector;


例:根据系统发行版信息判断 httpd 程序包的名称然后保存到一个变量中,并输出这个变量值。

$ cat test4.pp 
$webserver = $operatingsystem ? {
        /(?i-mx:ubuntu|debian)/                 => 'apache2',
        /(?i-mx:centos|fedora|redhat)/  => 'httpd',
}
notice($webserver)

执行结果如下:

$ puppet apply -v test4.pp
Notice: Scope(Class[main]): httpd
Notice: Compiled catalog for centos7-200 in environment production in 0.01 seconds
Info: Applying configuration version '1590206694'
Notice: Finished catalog run in 0.02 seconds

puppet 的类是用于公共目的的一组资源,是命名的代码块,创建后可在 puppet 全局调用,并且类可被继承。

定义

语法如下:

# 无参类
class class_name {
	puppet code...  
}
# 有参类
class class_name($var1,$var2='default value',...){
  puppet code...
}

类的名称只能以小写字母开头,可以包含小字字母、数字和下划线。

每个类都会引入一个新的变量 scope,这意味着在任何时候访问类中的变量时,都得使用其完全限定名称。

不过,在本地 scope 可以重新为 top scope 中的变量赋予一个新值。


例 1:定义一个用于 httpd 的类。

$ cat test5.pp 
class apache {
        package { httpd:
                ensure => installed
        }

        file { 'httpd.conf': 
                path => '/etc/httpd/conf/httpd.conf',
                ensure => file,
                require => Package['httpd'],
        }

        server { httpd:
                ensure => running,
                require => Package['httpd'],
                subscribe => File['httpd.conf'],
        }
}

例 2:定义一个用于 nginx 的类。

$ cat test6.pp 
# 如果是有参类,下面 class 的声明则可改为:
# class nginx($webserver=nginx) {
# 然后可以把 $webserver = nginx 去掉
class nginx {
        $webserver = nginx
        package { $webserver:
                ensure => latest,
                allow_virtual => false
        }

        file { '/etc/nginx/nginx.conf':
                ensure => file,
                source => '/root/puppetsource/nginx/nginx.conf',
                require => Package[$webserver],
                notify => Service['nginx'],
        }

        service { nginx:
                ensure => running,
                enable => true,
                hasrestart => true,
                hasstatus => true,
                # restart => 'systemctl reload nginx',
                require => [ Package[$webserver], File['/etc/nginx/nginx.conf'] ],
        }
}
include nginx

声明

在 manifest 文件中定义的类不会直接被执行,它们需要被事先声明后才能被执行。

声明类的方式有如下四种:

使用 include 声明:
	语法:include <class_name1>[,<class_name2>,...]
使用 require 声明:
	语法:require <class>
类似使用资源一样声明:
	语法:
		class { <class_name>:
			attr1 => value,
			attr2 => value,
			...
		}

例 1:使用 include 声明上面定义的 nginx 无参类。

# 将下面语句添加到 test6.pp 文件尾部
include nginx

例 2:使用声明资源的方式调用上面定义的 nginx 有参类。

# 将下面语句添加到 test6.pp 文件尾部
class { nginx:
	webserver => 'tengine',
}

类继承

类继承的作用主要是继承一个已有的类,并实现覆盖资源属性,或向资源属性追加额外值。

定义方式:

class [<base_class>::]<class_name> inherits <base_class> {}
    base_class:基类名,基类需事先存在;
  	class_name:子类名;

在子类中如果需要给基类的属性重新赋值则可使用 var => value 的方式,如果希望给基类的的资源属性追加额外值,则可使用 var +> value 的方式。

类继承时:

  • 声名子类时,其基类会被自动首先声明;
  • 基类成为了子类的父作用域,基类中的变量和属性默认值会被子类复制一份;
  • 子类可以覆盖父类中同一资源的相同属性的值:

例 1:使用继承的方式定义两个 nginx 子类,一个用来提供 web 服务,一个用来提供 proxy 服务。

$ cat test7.pp 
class nginx {
        package {'nginx':
                ensure => latest,
                allow_virtual => false,
        } ->

        service {'nginx':
                enable => true,
                ensure => running,
                hasrestart => true,
                hasstatus => true,
                restart => 'service nginx reload',
        }
}

class nginx::webserver inherits nginx{
        # 引用基类的资源并覆盖属性
        Package['nginx'] {
                name => 'tengine',
        }

        file{'/etc/nginx/nginx.cnf':
                source => '/root/puppetsource/nginx/nginx_web.conf',
                ensure => file,
                notify => Service['nginx'],
        }
}

class nginx::proxy inherits nginx{
        # 引用基类的资源并额外追加值
        Package['nginx'] {
                # 此处表示不仅安装基类指定的 nginx,还额外要安装 varnish 包
                name +> 'varnish'
        }
        file{'/etc/nginx/nginx.conf':
                source => '/root/puppetsource/nginx/nginx_proxy.conf',
                ensure => file,
                notify => Service['nginx'],
        }
}

include nginx::proxy

模板

模板的作用其实就是在静态文件中使用变量等编程元素生成适用于多种不同环境的文本文件,这个文本文件通常是配置文件。

puppet 模板语言使用的是基于 ruby 的 ERB(Embedded RuBy),用于实现在文本文件中嵌入 ruby 代码,原来的文本信息不会被改变,但 ruby 代码将会被执行,执行的结果将直接替换原来的代码。

ERB 在文本文件中的使用有如下几种:

  • <%= Ruby Expression %>:替换为表达式的值;
  • <% Ruby Expression %>:仅执行代码,而不替换;
  • <%# comment %>:文本注释;
  • <%%:转义,输出为 <%
  • %%>:转义,输出为 %>
  • <%- Ruby code %>:忽略空白字符;
  • <% Ruby code -%>:忽略空白行;

在模板中可以使用变量,包括 puppet 的任意可用变量,变量名须以 @ 字符开头。

更多 ruby 语法可参考 https://www.runoob.com/ruby/ruby-tutorial.html

在 mainfest 中使用模板文件时,一般需要通过 template 函数来渲染模板文件,比如:

file{'/etc/nginx/nginx.conf':
	content => template('/root/puppetsource/nginx/nginx_proxy.conf'),
	ensure => true,
}

模块

到目前为止,资源申报、定义类、声明类等所有功能都只能在一个 manifest 文件中实现,但这却非是最有效的基于 puppet 管理 IT 基础架构的方式。
实践中,一般需要把 manifest 文件分解成易于理解的结构,例如将类文件、配置文件甚至包括后面将提到的模块文件等分类存放,并且通过某种机制在必要时将它们整合起来。

这种机制即"模块”,它有助于以结构化、层次化的方式使用 puppet,而 puppet 则基 于“模块自动装载器”完成模块装载。

从另一个角度来说,模块实际上就是一个按约定的、预定义的结构存放了多个文件或子用录的目录,目录里的这些文件或子目录必须遵循其命名规范。

puppet 会按此种规范在特定位置查找所需的模块文件,不过,这些特定目录也可以通过 puppet 的配置参数 modulepath 定义。

目录结构

默认情况下,puppet 的模块目录为 /etc/puppet/modules,模块的目录组织结构规范如下:

module_name:
	manifests: manifest 文件目录
		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目录下的插件使用说明文档

管理命令

puppet 为模块提供了专门的管理子命令,其使用格式如下:

puppet module <action> [--environment production ] [--modulepath $basemodulepath ]
action:
  build        打包模块
  changes      查看改变信息
  generate     生成一个新模块
  install      安装模块
  list         查看已安装的模块列表
  search       从 Puppet forge 中搜索模块
  uninstall    卸载模块
  upgrade      升级模块

Puppet forge 是 puppet 公开在互联网上的一个模块仓库,可以直接从该仓库中下载安装模块。

以查看已安装的模块列表为例:

$ puppet module list
/etc/puppet/modules (no modules installed)
/usr/share/puppet/modules (no modules installed)

可以看到,默认情况下 puppet 从 /etc/puppet/modules/usr/share/puppet/modules 中查找模块。

如果希望自己构建一个模块,则可直接在模块根目录下创建对应结构的模块目录,以创建一个名为 nginx 的模块为例,执行下面命令:

$ mkdir -p /etc/puppet/modules/nginx/{manifests,files,templates,tests,lib,spec}

然后就以找到该模块:

$ puppet module list
/etc/puppet/modules
└── nginx (???)
/usr/share/puppet/modules (no modules installed)

示例

以将之前使用的 nginx 的 manifest 文件转换为模块形式为例,目录结构如下:

/etc/puppet/modules/nginx
├── files
│   └── nginx_web.conf
├── lib
├── manifests
│   ├── init.pp
│   ├── nginx_base.pp
│   ├── proxy.pp
│   └── webserver.pp
├── spec
├── templates
│   └── nginx_proxy.conf.erb
└── tests

其中,files/nginx_web.conftemplates/nginx_proxy.conf.erb 分别是配置文件和模板文件,我这里就不列出内容了。

manifests/nginx_base.pp 内容:

$ cat manifests/nginx_base.pp 
class nginx {
        package {'nginx':
                ensure => latest,
                allow_virtual => false,
        } ->

        service {'nginx':
                enable => true,
                ensure => running,
                hasrestart => true,
                hasstatus => true,
                restart => 'service nginx reload',
        }
}

manifests/init.pp 内容:

# init.pp 默认就会被最先执行
$ cat manifests/init.pp 
import 'nginx_base.pp'

manifests/proxy.pp 内容:

$ cat manifests/proxy.pp 
# 由于 init.pp 文件默认就被执行了,所以这里可以引用到 nginx_base.pp 中定义的 nginx 类
class nginx::proxy inherits nginx{
        file{'/etc/nginx/nginx.conf':
                content => template('nginx/nginx_proxy.conf.erb'),
                ensure => file,
                notify => Service['nginx'],
                require => Package['nginx'],
        }
}

manifests/webserver.pp 内容:

$ cat manifests/webserver.pp 
# 由于 init.pp 文件默认就被执行了,所以这里可以引用到 nginx_base.pp 中定义的 nginx 类
class nginx::webserver inherits nginx{
        file{'/etc/nginx/nginx.cnf':
                source => 'puppet:///modules/nginx/nginx_web.conf',
                ensure => file,
                notify => Service['nginx'],
                require => Package['nginx'],
        }
}

以声明模块中的 proxy 类为例,执行下面命令即可:

#  --modulepath 用来自定义模块查找目录,这里可省略
$ puppet apply -v --modulepath='/etc/puppet/modules' -e 'include nginx::webserver'
Warning: The use of 'import' is deprecated at /etc/puppet/modules/nginx/manifests/init.pp:2. See http://links.puppetlabs.com/puppet-import-deprecation
   (at grammar.ra:610:in `block in _reduce_190')
Notice: Compiled catalog for centos7-200 in environment production in 0.50 seconds
Info: Applying configuration version '1590223385'
Notice: /Stage[main]/Nginx/Package[nginx]/ensure: created
Notice: /Stage[main]/Nginx::Webserver/File[/etc/nginx/nginx.cnf]/ensure: defined content as '{md5}6cac890fd06c03b362666f6237a61a8f'
Info: /Stage[main]/Nginx::Webserver/File[/etc/nginx/nginx.cnf]: Scheduling refresh of Service[nginx]
Notice: /Stage[main]/Nginx/Service[nginx]/ensure: ensure changed 'stopped' to 'running'
Info: /Stage[main]/Nginx/Service[nginx]: Unscheduling refresh on Service[nginx]
Notice: Finished catalog run in 2.39 seconds

agent/master

默认情况下 agent/master 的工作模式如下:

  • agent:默认每隔 30 分钟向 master 发送 node name 和 facts 信息,并请求 catalog;

  • master:验证客户端身份,查找与其相关的 site manifest,编译生成 catalog,并发送给客户端;

要注意的是,agent 和 master 是基于 SSL 通信的,agent 要与 master 正常通信,master 必须签署 agent 的签署请求。


准备如下主机:

主机名IP安装程序包
master10.0.1.200puppet、puppet-server
agent10.0.1.201puppet

配置

puppet 的主配置文件为 /etc/puppet/puppet.conf,其是 ini 风格的配置文件,组成部分大致如下:

$ cat /etc/puppet/puppet.conf | egrep '^\s*#' -v
# 主配置,对 master 和 agent 都生效
[main]
		# 日志目录
    logdir = /var/log/puppet
		# 运行时目录
    rundir = /var/run/puppet
		# ssl 文件目录
    ssldir = $vardir/ssl
# 服务端配置,仅对 master 生效
[master]

# 客户端配置,仅对 agent 生效
[agent]
    classfile = $vardir/classes.txt

    localconfig = $vardir/localconfig

除了配置文件中配置的参数外,其还有一些默认配置,可通过 config 子命令查看,如下:

$ puppet config print
confdir = /etc/puppet
vardir = /var/lib/puppet
name = config
...

也可直接通过子命令的方式来设置参数值:

# 该设置将直接保存到主配置文件
$ puppet config set log_level notice

可以直接把当前环境所有参数信息以配置文件格式生成,如下:

# 生成 master 环境配置
$ puppet master --genconfig | egrep '^\s*#' -v | egrep '^\s*$' -v
[master]
    confdir = /etc/puppet
    vardir = /var/lib/puppet
    name = master
    ...
# 生成 agent 环境配置
$ puppet agent --genconfig | egrep '^\s*#' -v | egrep '^\s*$' -v
[agent]
    confdir = /etc/puppet
    vardir = /var/lib/puppet
    name = agent
    ...

注意:

  • 在生成新的配置之前不能删除或移动原有的 puppet.conf
  • 生成的配置中,有的参数已经被废弃,与现有 puppet 版本可能不兼容;
  • 有的参数的默认值与现在版本所支持的参数值可能不相兼容;

所以为稳妥起见还是建议在用到啥参数的时候往配置文件加就行了,而不要一股脑把所有参数都整进配置文件。

文档

puppet 默认就提供了很详细的说明文档,可通过 doc 子命令进行管理。

查看所有的文档:

$ puppet doc --list
configuration - A reference for all settings
function - All functions available in the parser
indirection - Indirection types and their terminus classes
metaparameter - All Puppet metaparameters and all their details
providers - Which providers are valid for this machine
report - All available transaction reports
type - All Puppet resource types and all their details

查看指定文档内容:

$ puppet doc -r configuration
...

运行

puppet 的 master/agent 模式是强依赖于主机名通信的,所以在运行之前需要事先做好 DNS 或 hosts 文件的解析,我这里就直接在两台主机的 /etc/hosts 文件中添加如下映射内容了:

10.0.1.200 master
10.0.1.201 agent

启动 master

在 master 主机测试以前台模式启动 puppet master 服务:

$ puppet master -v --no-daemonize
Info: Creating a new SSL key for ca
Info: Creating a new SSL certificate request for ca
Info: Certificate Request fingerprint (SHA256): 5E:A0:C6:22:D0:14:26:D6:F4:B3:DF:8B:3A:30:B3:49:E8:B0:8F:59:BA:CB:D0:8E:79:35:F4:AC:C2:FF:A5:4B
Notice: Signed certificate request for ca
Info: Creating a new certificate revocation list
Info: Creating a new SSL key for master
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for master
Info: Certificate Request fingerprint (SHA256): A4:BF:33:D5:07:03:0F:D3:7C:D3:61:84:5C:B3:13:55:8E:56:E7:4A:CF:35:97:16:98:33:B8:B1:D5:66:81:B2
Notice: master has a waiting certificate request
Notice: Signed certificate request for master
Notice: Removing file Puppet::SSL::CertificateRequest master at '/var/lib/puppet/ssl/ca/requests/master.pem'
Notice: Removing file Puppet::SSL::CertificateRequest master at '/var/lib/puppet/ssl/certificate_requests/master.pem'
Notice: Starting Puppet master version 3.6.2

前台正常启动检测无误后,可以中断它然后使用后台模式启动了:

$ systemctl start puppetmaster

启动完成后 master 主机的 8140 端口就处于监听状态了:

$ ss -tanl | grep :8140
LISTEN     0      128          *:8140                     *:*

启动 agent

在 agent 主机测试 agent 服务连接 master 服务:

$ puppet agent --server=master --no-daemonize --noop --test -v
Info: Creating a new SSL key for agent
Info: Caching certificate for ca
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for agent
Info: Certificate Request fingerprint (SHA256): B1:3F:88:8E:3B:A7:F9:37:A7:83:8D:F4:79:25:F6:D2:C6:DC:A3:22:F1:BD:D7:9B:8B:28:C7:5B:BE:1D:F9:5A
Info: Caching certificate for ca
Exiting; no certificate found and waitforcert is disabled

真正的发起连接:

$ puppet agent --server=master --no-daemonize -v

接下来在 master 端就会收到签署请求:

# 此种方式查看的是未签署的请求,可使用 --all 查看所有已签署的请求
$ puppet cert list
  "agent" (SHA256) B1:3F:88:8E:3B:A7:F9:37:A7:83:8D:F4:79:25:F6:D2:C6:DC:A3:22:F1:BD:D7:9B:8B:28:C7:5B:BE:1D:F9:5A

在 master 端签署请求:

# 也可使用 puppet cert sign --all 签署所有请求
$ puppet cert sign agent
Notice: Signed certificate request for agent
Notice: Removing file Puppet::SSL::CertificateRequest agent at '/var/lib/puppet/ssl/ca/requests/agent.pem'

然后 agent 与 master 就真正建立连接了,agent 输出信息如下:

$ puppet agent --server=master --no-daemonize -v
Info: Caching certificate for agent
Notice: Starting Puppet client version 3.6.2
Info: Caching certificate_revocation_list for ca
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for agent
Info: Applying configuration version '1590231028'
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 0.01 seconds

接下来就可以中断前台 agen 服务,在后台启动 agent 服务了:

$ systemctl start puppetagent

自动签署

我们可以通过配置文件的方式让 master 自动为符合指定规则的 agent 签署证书,该配置文件为 /etc/puppet/autosign.conf,默认不存在需要手动创建。

其规则定义格式很简单,只需要在该文件中加入主机名规则即可,比如:

web*

做完该配置后 master 将会自动为主机名以 web 开头的 agent 主机签署请求了。

站点清单

定义

站点清单需要在 master 端定义,默认的站点清单文件为 /etc/puppet/manifests/site.pp,清单定义格式如下:

# 格式一:以主机名直接给出相关定义
node 'node_name' {
  puppet code...
}

# 格式二:把功能相近的主机事先按统一格式命名,基于正则按统一格式调用
node /^web\d+/ {
	puppet code...  
}

# 格式三:节点继承
node basenode {
  puppet code...
}

node childnode inherits basenode {
	puppet code...  
}

站点清单的作用就是标识哪个 agent 该调用哪些模块,所以在编写站点清单之前我们就需要准备好相关模块。

当然,如果节点非常多,把所有节点都写在 site.pp 文件中显然有些冗杂了,此时我们可以将节点按分类在 /etc/puppet/manifests 下创建相应文件夹,然后在对应文件夹下创建单独的文件来定义该类型节点的站点清单。比如有如下目录结构:

/etc/puppet/manifests/
	site.pp
	webservers
	dataservers

此时如果想要 webservers 目录中的配置生效,则可直接在 site.pp 中导入该目录下的所有配置,如下:

import 'webservers/*.pp'

应用

在之前已经在 master 主机定义了 nginx 模块,我这里就直接以它做演示,让 agent 端调用 nginx 模块安装并启动 nginx 服务,编写清单内容如下:

$ vim /etc/puppet/manifests/site.pp
node 'agent' {
        include nginx::proxy
}

为能够直观的看到 agent 应用 master 模块的效果,这里先在 agent 主机停止 agent 服务:

$ systemctl stop puppetagent

在 master 主机重启 puppet master 服务:

$ systemctl restart puppetmaster

在 agent 主机前台启动 agent 服务:

$ puppet agent --server=master --no-daemonize -v
Notice: Starting Puppet client version 3.6.2
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for agent
Info: Applying configuration version '1590233933'
Notice: /Stage[main]/Nginx/Package[nginx]/ensure: created
Notice: /Stage[main]/Nginx/Service[nginx]/ensure: ensure changed 'stopped' to 'running'
Info: /Stage[main]/Nginx/Service[nginx]: Unscheduling refresh on Service[nginx]
Notice: Finished catalog run in 2.97 seconds

可以看到,agent 成功拉取应用了 master 的 catalog 并且安装启动了 nginx。

多环境支持

在 puppet master 端定义多环境:

[master]
# 标识支持的环境
environment = development, testing, production

[development]
manifests = /etc/puppet/manifests/development/site.pp
modulepath = /etc/puppet/modules/development/:/usr/share/modules/development
fileserverconfig = /etc/puppet/fileserver.conf.development

[testing]
manifests = /etc/puppet/manifests/testing/site.pp
modulepath = /etc/puppet/modules/testing/:/usr/share/modules/testing
fileserverconfig = /etc/puppet/fileserver.conf.testing
	
[production]
manifests = /etc/puppet/manifests/production/site.pp
modulepath = /etc/puppet/modules/production/:/usr/share/modules/production
fileserverconfig = /etc/puppet/fileserver.conf.production

在每个 puppet agent 端定义当前 agent 所述环境:

[agent]
# 标识当前 agent 所属的环境
environment = development

不管是 agent 还是 master 端默认的环境配置都是 production,可以通过如下方式查看:

# 服务端查看环境
$ puppet master --configprint environment
production
# 客户端查看环境
$ puppet agent --configprint environment
production

主动触发

1、在 agent 端设定 listen 参数值为 true

$ vim /etc/puppet/puppet.conf
[agent]
listen = true

2、在 agent 主机添加名称空间认证配置文件,用来限定指定主机才能触发 agent 的 puppet run 操作:

$ vim /etc/puppet/namespaceauth.conf
[puppetrun]
allow master

3、编辑认证文件授权 master 可访问的 URI:

$ vim /etc/puppet/auth.conf
path /run
method save
allow master
# 在下面的额 path / 之前添加
path /
auth any 

4、重启 agent 服务并检查 8139 端口是否处于监听状态:

$ systemctl restart puppetagent
$ ss -tanl | grep :8139
LISTEN     0      128          *:8139                     *:*

5、为直观看到效果,先卸载 agent 主机中的 nginx:

$ yum remove nginx -y
$ rm -rf /etc/nginx

6、在 master 主机使用 kick 子命令触发指定的 agent 拉取 catalog 并 run:

$ puppet kick agent
Getting status
status is success
agent finished with exit code 0
Finished

7、检查 agent 主机是否已安装并启动了 nginx:

$ rpm -q nginx
nginx-1.16.1-1.el7.x86_64

$ systemctl status nginx | grep Active
   Active: active (running) since Sun 2020-05-24 09:21:00 CST; 2min 8s ago
0

评论区