类是puppet中命名的代码模块,经常使用于定义一组通用目标的资源,可在puppet全局调用;
类能够被继承,也能够包含子类;
具体定义的语法以下:html
class NAME{ ... puppet code ... }
其中,在咱们定义的时候,须要注意的是:node
下面,咱们来看一个简单的例子:mysql
vim class1.pp class redis { #定义一个类 package{'redis': ensure => installed, } -> file{'/etc/redis.conf': ensure => file, source => '/root/manifests/file/redis.conf', owner => 'redis', group => 'root', mode => '0640', tag => 'redisconf' } ~> service{'redis': ensure => running, enable => true, hasrestart => true, hasstatus => true } } include redis #调用类
注意:类只有被调用才会执行。include后能够跟多个类,直接用","隔开便可。redis
咱们定义的类也能够进行参数设置,能够进行参数的传递。
具体语法以下所示:sql
class NAME(parameter1, parameter2) { #注意,大括号前有一个空格 ...puppet code... }
咱们来看一个例子:编程
vim class2.pp class instpkg($pkg) { package{"$pkg": ensure => installed, } } class{"instpkg": #给参数传入值 pkg => 'memcached', }
注意:单个主机上不能被直接声明两次。
若是对应的参数未传值的话,执行会报错。
可是咱们能够在定义形参的时候,设定一个默认值,这样的话,咱们不传入值的话,就会自动调用默认值:vim
vim class3.pp class instpkg($pkg='wget') { package{"$pkg": ensure => installed, } } include instpkg
这样的话,咱们直接使用include
调用便可,就不须要给参数传入值了。
由上,咱们能够总结出,调用类的方式有两种:服务器
1. include CLASS_NAME1, CLASS_NAME2, ... 2. class{'CLASS_NAME': attribute => value, }
咱们来看一个比较全面的例子:
首先,判断咱们系统的版本,是6仍是7,由此来肯定,是安装mysql
仍是mariadb
,同时,使用调用参数的方式来实现如上需求。
具体实现的代码以下:架构
vim dbserver.pp class dbserver($dbpkg='mariadb-server',$svc='mariadb') { #定义类并给参数赋值 package{"$dbpkg": ensure => installed, } service{"$svc": ensure => running, enable => true, hasrestart => true, hasstatus => true, } } if $operatingsystem == 'CentOS' { if $operatingsystemmajrelease == '7' { include dbserver #直接调用类 } else { class{"dbserver": #调用类并对参数从新赋值 dbpkg => 'mysql-server', svc => 'mysqld' } } }
相似于其它编程语言中的类的功能,puppet 的Class 能够被继承,也能够包含子类。
其定义的语法以下:app
class SUB_CLASS_NAME inherits PARENT_CLASS_NAME { ...puppet code... }
下面咱们来看一个例子:
vim class4.pp class redis { #定义class类 package{'redis': ensure => installed, } service{'redis': ensure => running, enable => true, } } class redis::master inherits redis { #调用父类 file {'/etc/redis.conf': ensure => file, source => '/root/manifests/file/redis-master.conf', owner => 'redis', group => 'root', } Service['redis'] { #定义依赖关系 subscribe => File['/etc/redis.conf'] } } class redis::slave inherits redis { #调用父类 file {'/etc/redis.conf': ensure => file, source => '/root/manifests/file/redis-slave.conf', owner => 'redis', group => 'root', } Service['redis'] { #定义依赖关系 subscribe => File['/etc/redis.conf'] } }
同样的,咱们的类在调用的时候,能够实现修改原有值和额外新增属性的功能。
咱们的继承父类的时候,能够定义一些父类本来没有的属性:
在继承的类中,咱们能够在属性原有值的基础上,使用 +> 进行新增修改:
在继承的类中,咱们能够直接把原有的值进行覆盖修改,使用 =>
进行覆盖便可:
在继承的类中,咱们还能够在总体调用的基础上,根据不一样的需求,把父类中的部分值进行重写修改:
模板一般以erb
结尾。模板均使用erb
语法。
关于puppet
兼容的erb
语法,咱们能够去官方文档查看,下面附上官方文档地址:https://docs.puppet.com/puppet/latest/reference/lang_template_erb.html
如下,附上部分重要内容:
<%= EXPRESSION %> — 插入表达式的值,进行变量替换 <% CODE %> — 执行代码,但不插入值 <%# COMMENT %> — 插入注释 <%% or %%> — 插入%
接着咱们来看一个实例:
咱们使用puppet 模板来实现,将redis 监听端口修改成本机的ip地址。
首先,咱们先来定义一个file.pp
文件,在该文件中调用咱们的模板:
vim file.pp file{'/tmp/redis.conf': #仅用于测试模板是否生效,因此放在tmp目录下 ensure => file, content => template('/root/manifests/file/redis.conf.erb'), #调用模板文件 owner => 'redis', group => 'root', mode => '0640', }
接着,咱们去修改配置文件的源,也就是咱们的模板文件:
vim file/redis.conf.erb bind 127.0.0.1 <%= @ipaddress_eth0 %> #修改监听端口
修改完成之后,咱们就能够执行查看结果了:
puppet apply -v file.pp
而后,咱们去查看一下/tmp/redis.conf
文件:
vim /tmp/redis.conf
能够看出,咱们的变量替换已经成功。
实践中,通常须要把manifest 文件分解成易于理解的结构,例如将类文件、配置文件甚至包括后面将提到的模块文件等分类存放,而且经过某种机制在必要时将它们整合起来。
这种机制即模块,它有助于以结构化、层次化的方式使用puppet,而puppet 则基于“模块自动装载器”。
从另外一个角度来讲,模块实际上就是一个按约定的、预约义的结构存放了多个文件或子目录的目录,目录里的这些文件或子目录必须遵循其命名规范。
模块的目录格式以下:
其中,每一个文件夹中存放的内容及其要求以下:
puppet:///modules/MODULE_NAME/FILE_NAME
;tempate('MOD_NAME/TEMPLATE_FILE_NAME')
; 下面咱们就来看一个实例来具体的了解应该如何定义一个模块:
1)咱们先来建立对应的目录格式:
[root@master ~]# mkdir modules [root@master ~]# cd modoules/ [root@master modules]# ls [root@master modules]# mkdir -pv redis/{manifests,files,templates,tests,lib,spec} mkdir: created directory ‘redis’ mkdir: created directory ‘redis/manifests’ mkdir: created directory ‘redis/files’ mkdir: created directory ‘redis/templates’ mkdir: created directory ‘redis/tests’ mkdir: created directory ‘redis/lib’ mkdir: created directory ‘redis/spec’
2)目录格式建立完成以后,咱们就能够来建立对应的父类子类文件了。
首先,咱们来建立父类文件:
[root@master modules]# cd redis/ [root@master redis]# vim manifests/init.pp class redis { package{'redis': ensure => installed, } -> service{'redis': ensure => running, enable => true, hasrestart => true, hasstatus => true, require => Package['redis'], } }
建立完成后,咱们再来建立对应的子类文件:
[root@master redis]# vim manifests/master.pp class redis::master inherits redis { file {'/etc/redis.conf': ensure => file, source => 'puppet:///modules/redis/redis-master.conf', owner => 'redis', group => 'root', mode => '0640', } Package['redis'] -> File['/etc/redis.conf'] ~> Service['redis'] } [root@master redis]# vim manifests/slave.pp class redis::slave($master_ip,$master_port='6379') inherits redis { file {'/etc/redis.conf': ensure => file, content => template('redis/redis-slave.conf.erb'), owner => 'redis', group => 'root', mode => '0640', } Package['redis'] -> File['/etc/redis.conf'] ~> Service['redis'] }
3)准备文件:
如今咱们须要把模板文件准备好,放入咱们的templates
目录下:
scp redis.conf.erb /root/modules/redis/templates/redis-slave.conf.erb
还有咱们的静态文件,也要放入咱们的files
目录下:
scp redis.conf /root/modules/redis/files/redis-master.conf
4)查看目录结构,肯定咱们是否都已准备完成:
[root@master modules]# tree . └── redis ├── files │ └── redis-master.conf ├── lib ├── manifests │ ├── init.pp │ ├── master.pp │ └── slave.pp ├── spec ├── templates │ └── redis-slave.conf.erb └── tests 7 directories, 5 files
5)如今就能够把咱们的准备好的模块放入系统的模块目录下:
[root@master mdoules]# cp -rp redis/ /etc/puppet/modules/
注意,模块是不能直接被调用的,只有放在/etc/puppet/modules
下,或/usr/share/puppet/modules
目录下,使其生效才能够被调用。
咱们能够来查看一下咱们的模块到底有哪些:
[root@master mdoules]# puppet module list /etc/puppet/modules └── redis (???) /usr/share/puppet/modules (no modules installed)
能够看出,咱们的模块已经定义好了,如今咱们就能够直接调用了。
6)调用模块
咱们能够直接命令行传入参数来调用咱们准备好的模块:
[root@master modules]# puppet apply -v --noop -e "class{'redis::slave': master_ip => '192.168.37.100'}" #若是有多个参数,直接以逗号隔开便可
也能够把咱们的调用的类赋值在.pp
文件中,而后运行该文件。
[root@master ~]# cd manifests/ [root@master manifests]# vim redis2.pp class{'redis::slave': master_ip => '192.168.37.100', } [root@master manifests]# puppet apply -e --noop redis2.pp
以上。实验完成。
注意,以上实验是咱们在单机模式下进行的,若是是要在master/agent 模式下进行,步骤还会略有不一样。
master/agent模型时经过主机名进行通讯的,下面,就来看看 master-agent 模式的puppet运维自动化如何实现:
1)下载包
master 端:puppet.noarch
,puppet-server.noarch
agent 端:puppet.noarch
2)主机名解析
为了方便咱们后期的操做,咱们能够经过定义/etc/hosts
文件实现主机名的解析。若是机器不少的话,可使用DNS进行解析。
[root@master ~]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.37.111 master.keer.com 192.168.37.122 server1.keer.com
注意,该操做须要在每一台主机上进行。
修改完成之后,咱们能够来测试一下是否已经成功:
[root@master ~]# ping server1.keer.com
3)时间同步
[root@master ~]# systemctl start chronyd.service
全部机器上都开启chronyd.service
服务来进行时间同步
开启事后能够查看一下状态:
[root@master ~]# systemctl status chronyd.service
咱们可使用chronyc sources
命令来查看时间源:
1)手动前台开启,观察服务开启过程:
puppet master -v --no-daemonize #前台运行
2)直接systemctl
开启服务,监听在8140端口。
1)在配置文件中指明server端的主机名:
[root@server1 ~]# vim /etc/puppet/puppet.conf server = master.keer.com
接着,咱们能够经过puppet config print
命令来打印输出咱们配置的参数:
[root@server1 ~]# puppet config print 显示配置文件中的配置参数 [root@server1 ~]# puppet config print --section=main 显示main 段的配置参数 [root@server1 ~]# puppet config print --section=agent 显示agent 段的配置参数 [root@server1 ~]# puppet config print server 显示server 的配置参数
2)开启 agent 服务
咱们能够发现,他会一直卡在这里等待CA颁发证书。
3)在 master 端签署证书
[root@master ~]# puppet cert list "server1.keer.com" (SHA256) B5:67:51:30:5C:FB:45:BA:7A:73:D5:C5:87:D4:E3:1C:D7:02:BE:DD:CC:7A:E2:F0:28:34:87:86:EF:E7:1D:E4 [root@master ~]# puppet cert sign server1.keer.com #颁发证书 Notice: Signed certificate request for server1.keer.com Notice: Removing file Puppet::SSL::CertificateRequest server1.keer.com at '/var/lib/puppet/ssl/ca/requests/server1.keer.com.pem'
master 端管理证书部署的命令语法以下:
puppet cert <action> [–all|-a] [<host>]
action:
list 列出证书请求
sign 签署证书
revoke 吊销证书
clean 吊销指定的客户端的证书,并删除与其相关的全部文件;
注意:某agent证书手工吊销后从新生成一次;
On master host:
puppet cert revoke NODE_NAME
puppet cert clean NODE_NAME
On agent host:
从新生成的主机系统,直接启动agent;
变换私钥,建议先清理/var/lib/puppet/ssl/目录下的文件
4)终止服务开启,再次开启
[root@server1 ~]# puppet agent -v --noop --no-daemonize
能够看出咱们的服务开启成功,可是因为master 端没有配置站点清单,因此没有什么动做。
1)设置站点清单
① 查询站点清单应存放的目录,(能够修改,去配置文件修改)
[root@master ~]# puppet config print |grep manifest
[root@master ~]# cd /etc/puppet/manifests/ [root@master manifests]# vim site.pp node 'server1.along.com' { include redis::master }
分析:就是简单的调用模块,只有模块提早定义好就能够直接调用;我调用的是上边的redis 模块
2)给puppet 用户受权
由于agent 端要来master 端读取配置,身份是puppet
[root@master manifests]# chown -R puppet /etc/puppet/modules/redis/*
3)[root@server1 ~]# puppet agent -v --noop --no-daemonize 手动前台开启agent 端服务
(4)直接开启服务,agent 会自动去master 端获取配置
[root@server1 ~]# systemctl start puppetagent 包已下载,服务也开启了
机器名称 | IP配置 | 服务角色 |
---|---|---|
puppet-master | 192.168.37.111 | puppet的master |
puppet-server1-master-redis | 192.168.37.122 | puppet的agent,redis 的master |
puppet-server2-slave-redis | 192.168.37.133 | puppet的agent,redis 的slave |
1)下载包
master 端:puppet.noarch
,puppet-server.noarch
agent 端:puppet.noarch
2)主机名解析
为了方便咱们后期的操做,咱们能够经过定义/etc/hosts
文件实现主机名的解析。若是机器不少的话,可使用DNS进行解析。
[root@master ~]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.37.111 master.keer.com 192.168.37.122 server1.keer.com 192.168.37.133 server2.keer.com
注意,该操做须要在每一台主机上进行。
修改完成之后,咱们能够来测试一下是否已经成功:
[root@master ~]# ping server1.keer.com
3)时间同步
[root@master ~]# systemctl start chronyd.service
三台机器上都开启chronyd.service
服务来进行时间同步
开启事后能够查看一下状态:
[root@master ~]# systemctl status chronyd.service
咱们可使用chronyc sources
命令来查看时间源:
(1)开启服务
[root@master ~]# systemctl start puppetmaster [root@server1 ~]# systemctl start puppetagent [root@server2 ~]# systemctl start puppetagent
由于server2 是第一次链接,需master 端签署证书
(2)master 签署颁发证书
[root@master manifests]# puppet cert list [root@master ~]# puppet cert sign server2.keer.com
[root@master manifests]# cd /etc/puppet/manifests [root@master manifests]# vim site.pp 直接调上边完成的模块 node 'server1.keer.com' { include redis::master } node 'server2.keer.com' { class{'redis::slave': master_ip => 'server1.keer.com' } }
[root@server2 ~]# vim /etc/redis.conf
[root@server2 ~]# redis-cli -a keerya info Replication
(1) 建立一个 chrony 模块,前准备
[root@master ~]# cd modules/ 进入模块工做目录 [root@master modules]# mkdir chrony 建立chrony 的模块 [root@master modules]# mkdir chrony/{manifests,files} -pv 建立模块结构
(2)配置chrony 模块
[root@master modules]# cd chrony/ [root@master chrony]# cp /etc/chrony.conf files/ [root@master puppet]# vim files/chrony.conf # test #用于测试实验结果
[root@master chrony]# vim manifests/init.pp class chrony { package{'chrony': ensure => installed } -> file{'/etc/chrony.conf': ensure => file, source => 'puppet:///modules/chrony.conf', owner => 'root', group => 'root', mode => '0644' } ~> service{'chronyd': ensure => running, enable => true, hasrestart => true, hasstatus => true } }
(3)puppet 添加这个模块,并生效
[root@master modules]# cp -rp chrony/ /etc/puppet/modules/ [root@master modules]# puppet module list
[root@master ~]# cd /etc/puppet/manifests/ [root@master manifests]# vim site.pp node 'base' { include chrony } node 'server1.keer.com' inherits 'base' { include redis::master } node 'server2.keer.com' inherits 'base' { class{'redis::slave': master_ip => 'server1.keer.com' } } #node /cache[1-7]+\.keer\.com/ { #能够用正则匹配多个服务器使用模块 # include varnish #}
咱们如今直接去server2机器上,查看咱们的配置文件是否已经生效,是不是咱们添加过一行的内容:
[root@server2 ~]# vim /etc/chrony.conf
发现咱们的实验成功。