目录

1、引语

2、puppet模块目录结构

3、各资源清单的编写

4、配置文件及模板文件准备

5、测试

6、总结    

1、引语

    在上一次博文(http://zhaochj.blog.51cto.com/368705/1661642)中已完成puppet的master/agent环境的部署,agent端也能够接收master端推送或每30分钟后向master请求catalog,我们还编写了一个简单的tengine模块进行测试,但在生产环境中编写的模块并不是你的生产环境中的一个服务或应用,而是puppet agent本身,仔细想一下就能想明白,假如你想调整一下agent端自动到master请求catalog的时间,你想配置agent支持kick功能,想调整一下puppet的配置文件等,那master端就要对puppet本身做管理,所以你就得编写一个模块来做这些工作。

2、puppet模块目录结构

    现在开始规划puppet模块的组织结构,目录树如下:

[root@nod1 modules]# pwd
/etc/puppet/modules
[root@nod1 modules]# tree puppet/
puppet/      #模块名
├── files   #存放一些模块中所需要的配置文件等
│   └── namespaceauth.conf    #agent支持kick的相关文件
├── manifests    #资源清单目录
│   ├── config.pp  #涉及到配置文件的资源清单
│   ├── init.pp       #资源清单的开始位置
│   ├── install.pp  #关于puppet,facter软件的管理文件
│   ├── params.pp   #一些变量所在的文件
│   └── service.pp   #关于puppet服务的文件
└── templates    #模板目录
    ├── auth.conf.erb   #认证用的模板
    └── puppet.conf.erb   #puppet的配置文件模板

上边的这些目录结构请自行创建。

    puppet这个模块大概是这样的,install.pp清单定义puppet、facter软件包的目标状态,得先有这两个软件包,那才能谈接下来的配置文件这些,这个清单的定义的主要是实现对软件的升级管理用;config.pp主要是对puppet的各个配置文件的管理,而service是管理puppet服务状态的,params.pp定义了一些变量和判断语句,便于在其他清单中进行引用。接下来对这些清单文件一一剖析。

3、各资源清单的编写

[root@nod1 puppet]# pwd
/etc/puppet
[root@nod1 puppet]# vim manifests/site.pp
node "nod1.test.com" {   #定义一个节点清单
        include puppet   #包含puppet模块
}

如果所有节点都是使用相同的模板,那可以写成下边的样子:

node default {
       include puppet
}

这个site.pp是所有模块调用的入口,你想运用哪些模块,只要在此文件中包含进来即可。

[root@nod1 modules]# vim puppet/manifests/init.pp
class puppet {
        include puppet::install,puppet::config,puppet::service
}


解释:init.pp是资源清单的入口,所有的资源引用都是从这里进入,这个文件中只定义了一个class,名为puppet,这个名称必须与模块名称相同,即“/etc/puppet/modules/puppet”的基名相同。其他pp文件中定义的类都是以puppet类为父类定义的相应子类,include语句中引用了三个类,puppet::install这个类表示install.pp文件中定义的类,puppet::config这个类表示config.pp文件中定义的类,puppet::service表示在service.pp文件中定义的类。

[root@nod1 modules]# vim puppet/manifests/install.pp
class puppet::install {
        include puppet::puppet_install,puppet::facter_install   #包含了两个类,分别定义puppet与facter,在下边有定义,
}
class puppet::puppet_install {
        package {'puppet':
                ensure => $operatingsystemmajrelease ? {
   #这里做条件判断
                        6 => '3.3.1-1.el6',
                }
        }
}
class puppet::facter_install {
        package {'facter':
                ensure => $operatingsystemmajrelease ? {
   #这里也是做条件判断
                        6 => '1.7.3-1.el6',
                }
        }
}

解释:这个资源清单定义了puppet与facter两个软件包的状态,可以根据agent系统的版本来定义安装的软件版本。

[root@nod1 modules]# vim puppet/manifests/config.pp
class puppet::config {
        include puppet::params  #因config.pp会调用变量,所以先要引用params.pp文件
        file {'/etc/puppet/puppet.conf':  #定义puppet.conf文件的属性
                ensure  => file,
                content => template('puppet/puppet.conf.erb'),
                owner   => 'root',
                group   => 'root',
                mode    => '0644',
                require => Class['puppet::install'],  #定义依赖关系,表示puppet.conf这个资源是在puppet安装之后
                notify  => Class['puppet::service'],  #表示puppet.conf文件被修改后要通知service重新加载服务
        }
        file {'/etc/puppet/auth.conf':  #定义认证文件的属性
                ensure   => file,
                content  => template('puppet/auth.conf.erb'),   #引用模板生成配置文件
                owner   => 'root',
                group   => 'root',
                mode    => '0644',
                require => Class['puppet::install'],  #表示puppet软件安装之后才配置auth.conf文件
                notify  => Class['puppet::service'],  #auth.conf文件被修改后通知service重新加载服务
        }
        file {'/etc/puppet/namespaceauth.conf':  #定义命名空间认证文件
                ensure  => file,
                source  => 'puppet:///modules/puppet/namespaceauth.conf',   #定义namespaceauth.conf文件的下载路径,注意puppet 下的files文件不需要写明
                owner   => 'root',
                group   => 'root',
                mode    => '0644',
                require => Class['puppet::install'],
                notify  => Class['puppet::service'],
        }
}

解释:config.pp资源清单主要配置一些配置文件的属性,配置文件一般会有依赖关系。

[root@nod1 modules]# vim puppet/manifests/service.pp 
class puppet::service {
        service {'puppet':
                ensure    => running,   #表示puppet是运行状态
                enable    => true,  #表示puppet开机启用
                hasrestart => true,  #表示以标准的方式重启服务,即调用“/etc/rc.d/init.d/”下的脚本
                hasstatus => true, #表示经标准方式探测服务的运行状态
                path      => '/etc/rc.d/init.d/',   #指定服务脚本的路径
                restart   => '/etc/rc.d/init.d/puppet reload',  #修改restart操作为reload
                require  => Class['puppet::install'],  #puppet软件先安装好后,服务才能运行
        }
}

解释:这个资源清单文件定义了puppet服务的一些属性,并修改了restart操作为reload操作,因为有这样的需要,当配置文件修改后,只是重新载入一下配置文件即可,在这里对于puppet服务来说重启与重新载入都不会产生什么不良的影响,但有些服务可不是这样。

[root@nod1 modules]# vim puppet/manifests/params.pp
class puppet::params {
        $puppetserver = 'nod1.test.com'    #声明一个变量
        case $operatingsystemmajrelease {   #引用了一个facter变量做系统发行版本判断应该装哪个版本的puppet和facter,这里我只列举了一个,可以扩充,在测试中发现我在install.pp中无法引用下边定义的“ $puppet_release”和“$facter_release”两个变量,所以在install.pp文件中直接做判断
                6: {
                        $puppet_release = '3.3.1-1.el6'  
                        $facter_release = '1.7.3-1.el6'
                }
                default: {   #在case语句中一定要有default语句,不然会报错
                        fail("Module puppet is not supported on ${::operatingsystem}")
                }
        }
}


解释:这个资源清单就是声明一些变量,定义判断语句的,case条件判断语句的格式如下:

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


4、配置文件及模板文件准备

接下来准备所需要的配置文件及模板文件:

[root@nod1 modules]# vim puppet/files/namespaceauth.conf
[puppetrunner]
allow *.test.com
#这是定义kick功能时的权限访问控制
[root@nod1 modules]# vim puppet/templates/auth.conf.erb
#这个文件就是在agent端的/etc/puppet/auth.conf配置文件的基础上增加了下边的代码
##puppet master
path /run
method save
allow <%= scope.lookupvar('puppet::params::puppetserver') %>


#这段代码必须在"path  /"之前,“<%= scope.lookupvar('puppet::params::puppetserver') %>”这是模板文件中引用变量的方式,这个变量引用过来就是“nod1.test.com”。

[root@nod1 modules]# vim puppet/templates/puppet.conf.erb
[main]
    logdir = /var/log/puppet
    rundir = /var/run/puppet
    ssldir = $vardir/ssl
[agent]
    classfile = $vardir/classes.txt
    localconfig = $vardir/localconfig
    server = <%= scope.lookupvar('puppet::params::puppetserver') %>
    listen = true   #定义支持kick功能,让puppet监听在tcp的8139端口
    runinterval = 900  #定义去master端获取catalog的间隔时间,单位为秒
#这个文件是/etc/puppet/puppet.conf去掉注释与空白行的数据。


5、测试

启动master端上的服务:

[root@nod1 modules]# service puppetmaster start
Starting puppetmaster:                                     [  OK  ]


再把agent上的facter软件版本降低:

[root@nod2 ~]# rpm -e facter --nodeps
[root@nod2 ~]# rpm -ivh facter-1.7.2-1.el6.x86_64.rpm
warning: facter-1.7.2-1.el6.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID 4bd6ec30: NOKEY
Preparing...                ########################################### [100%]
   1:facter                 ########################################### [100%]
[root@nod2 ~]# facter -v
1.7.2
[root@nod2 ~]# yum list facter --showduplicates  #查看yum中有哪些版本的facter
Loaded plugins: fastestmirror, priorities
Loading mirror speeds from cached hostfile
 * base: mirror.bit.edu.cn
 * epel: mirrors.neusoft.edu.cn
 * extras: mirrors.cqu.edu.cn
 * updates: ftp.yz.yamagata-u.ac.jp
Installed Packages
facter.x86_64                                                 1:1.7.2-1.el6                                                 installed
Available Packages
facter.x86_64                                                 1.6.18-8.el6                                                  epel      
facter.x86_64                                                 1:1.7.3-1.el6                                                 puppetrepo
facter.x86_64                                                 1:1.7.6-1.el6

                                              puppetrepo

#这里的puppetrepo是自己制作的puppet软件包源

[root@nod2 x86_64]# puppet agent -t --no-daemonize --noop
   #先做测试
Notice: Ignoring --listen on onetime run
Info: Retrieving plugin
Info: Caching catalog for nod2.test.com
Info: Applying configuration version '1434507925'
Notice: /Stage[main]/Puppet::Facter_install/Package[facter]/ensure: current_value 1.7.2-1.el6, should be 1.7.3-1.el6 (noop)
   #这里发现了版本与定义的不一致
Notice: Class[Puppet::Facter_install]: Would have triggered 'refresh' from 1 events
Notice: /Stage[main]/Puppet::Service/Service[puppet]/ensure: current_value stopped, should be running (noop)
   #这里发现服务没有启动
Info: /Stage[main]/Puppet::Service/Service[puppet]: Unscheduling refresh on Service[puppet]
Notice: Class[Puppet::Service]: Would have triggered 'refresh' from 1 events
Notice: Stage[main]: Would have triggered 'refresh' from 2 events
Notice: Finished catalog run in 0.73 seconds
[root@nod2 x86_64]# puppet agent -t --no-daemonize
   #强制执行
Notice: Ignoring --listen on onetime run
Info: Retrieving plugin
Info: Caching catalog for nod2.test.com
Info: Applying configuration version '1434507925'
Notice: /Stage[main]/Puppet::Facter_install/Package[facter]/ensure: ensure changed '1.7.2-1.el6' to '1.7.3-1.el6'
  #版本已发生改变
Notice: /Stage[main]/Puppet::Service/Service[puppet]/ensure: ensure changed 'stopped' to 'running'
Info: /Stage[main]/Puppet::Service/Service[puppet]: Unscheduling refresh on Service[puppet]
Notice: Finished catalog run in 11.40 seconds
You have new mail in /var/spool/mail/root
[root@nod2 x86_64]# facter -v
    #查看facter版本
1.7.3


再在agent上修改一下配置文件的内容后再执行一次看一下文件会不会被还原:

[root@nod2 x86_64]# echo "###" >> /etc/puppet/namespaceauth.conf 
You have new mail in /var/spool/mail/root
[root@nod2 x86_64]# cat /etc/puppet/namespaceauth.conf
[puppetrunner]
allow *.test.com
###
[root@nod2 x86_64]# puppet agent -t --no-daemonize
[root@nod2 x86_64]# cat /etc/puppet/namespaceauth.conf
  #文件内容被成功还原了
[puppetrunner]
allow *.test.com


再去查看一下auth.conf与puppet.conf都是我们在master端定义好的文件内容。

至此测试已结束。

6、总结    

    一个模块的编写并不是像我当初想像的那么困难,但这次测试中关于变量的引用问题还是依然没有解决,在网上查了一些资料,我引用的方法似乎没有错误,但对install.pp文件反复排查,发现在params.pp中定义的变量始终无法引用,不知为何?

puppet模块文件保存在:https://github.com/zhaochj/myrepository/tree/master/puppet_modules