1  概述


Puppet通过master/agent模型的方式,实现环境中的agent能主动同步master定义的状态。实现配置的统一。同时,我个人认为多环境是master/agent模型的扩展,因此放到到同一篇文章中介绍。


2  Master/agent模型的


2.1  概念介绍


默认agent端会每30分钟请求一次master以便来获取自己的catalog。master端这时候会根据agent端所持有的证书验证请求者的身份,并根据证书内嵌的使用者名称和请求者自己的名称进行解析验证,如果验证通过master端就根据节点定义找到属于请求者agent端的配置,并在本地编译成catalog,将编译完成的结果发送给agent端。

master端的一个固定位置放置模块。master模块是为了实现共享的,但是哪些主机能调用这些资源是定义在manifests的site.pp里。在puppet中,只要主机名有规律可寻,可以使用通配符或者正则表达式的模式来定义在mainfist里。所以可以用于定义匹配一台或者多台主机。

通过https的双向认证后通信的,puppet自己会维护CA,puppet有内建的私有CA。agent在第一次连接master的时候,会生成一个请求证书,发给master,这个证书需要人为审核是否信任的agent后签发完成证书的认证,也可以开启自动签发证书的功能,但是,出于安全考虑,不建议这么操作。

master和agent的相互识别是通过主机名来实现的,如果站点规模大,靠hosts文件解析不合适,所以就需要通过dns来解析主机名,这个dns仅需要为内网服务器提供解析,即需要建立私网内的dns。如果是双机房,那么机房间是通过专线来通信,一般可以用一个puppet server管理多机房里的主机。私有dns也可以仅在一个机房里创建。

master/agent:agent每隔30分钟到master端请求与自己相关的catalog。站点清单定义如下:

master: site manifest
node 'node_name' {
...puppet code...
}
node_name

程序包下载路径:

https://yum.puppetlabs.com/

官方文档:

https://docs.puppet.com/puppet/3/reference/

内建函数:

https://docs.puppet.com/puppet/3/reference/function.html

配置参数列表:

https://docs.puppet.com/puppet/3/reference/configuration.html

部署master:

安装程序包:facter, puppet, puppet-server 

初始化master:

puppet master --no-daemonize --verbose 

生成一个完整的配置参数列表:

puppet master --genconfig #查看有效配置,有分段,可以覆盖配置文件,一般不用这个操作

puppet agent --genconfig  

打印基于默认配置生效的各配置参数列表:

puppet config <action> [--section SECTION_NAME]

puppet  config  print  #打印的是默认配置,这里打印出来的配置是没有分段的

基于命令行设定某参数的值:

puppet config set 

格式:puppet config set [--section SECTION_NAME] [setting_name] [setting_value]

例子

puppet config set --section main master  master.sunny.com

master端管理证书签署:

puppet cert <action> [--all|-a] [<host>]

action:

list

sign

revoke

clean:吊销指定的客户端的证书,并删除与其相关的所有文件;

证书可以自动签署,但是出于安全考虑,一般不开启该功能

注意,某agent证书手工吊销后重新生成一次,

在master端:执行如下命令吊销和清除证书

         puppet cert  revoke NODE_NAME
         puppet cert clean NODE_NAME

在agent端:清除客户端的/var/lib/puppet/ssl下的内容

执行 


         rm -rf  /var/lib/puppet/ssl/*

客户端重启agent服务即可

systemctl restart puppetagent

在服务器查看到证书请求,然后签署即可完成证书的重新签署

如果要实现服务器端的自动签发证书,服务器端操作如下,

两种方法

方法一

在/etc/puppet下新加配置文件autosign.conf,将要自动签发的域名写入该文件

vim /etc/puppet/autosign.conf
*.sunny.com

方法二

在配置文件的main端添加如下内容,但是会导致所有的主机都会被签发,不建议。

vim /etc/puppet/puppet.conf
autosign = true

自动签发证书功能不建议打开,建议在第一次部署环境时使用,其他情况,建议关闭该功能,用手动签发证书操作。

在agent 端重新生成,重启服务即可

主机故障后,重新生成的主机系统,不需要做任何清理,只需要重启agent.

如果因私钥变更了,那么建议先清理/var/lib/puppet/ssl目录下的文件,然后在agent重启服务,服务器端再次签署证书,重新生成证书

站点清单的定义:

主机名定义:

主机名(主机角色)#-机架-机房-运营商-区域.域名

www1-rack1-yz-unicom-bj.magedu.com 

/etc/puppet/manifests/site.pp模板

node 'base' {
include ntp #假设有个类叫ntp
}
node 'HOSTNAME' {
...puppet code...
}
node /PATTERN/ {
...puppet code...
}
node /node[0-9]+\.magedu\.com/  #正则表达式,表示node节点后跟上1位以上的数字,都可以被匹配
#节点定义的继承:
node NODE inherits PAR_NODE_DEF {
...puppet code...
}
nodes/

清单配置信息可模块化组织:

databases.d/

tomcatservers.d/

nodes.d/:可通过多个pp文件分别定义各类站点的清单;而后统一导入site.pp,方法如下:

site.pp文件使用中如下配置:

import 'nodes/*.pp'

主机节点可以跟类一样,可以继承,假如节点太多,写在一个文件里,管理也不方便,因此需要通过模块化管理。

模块化例子如下

在路径/etc/puppet/manifests下创建多个以.d结束的目录,用来存放模块化的配置文件

mkdir /etc/puppet/manifests/websvrs.d
mkdir /etc/puppet/manifests/dbsvrs.d

然后在这些目录下模块化编写以.pp为后缀的文件

加载模块化,用import导入

node 'agent72.sunny.com' {
    include redis::master
    class{'tomcat':
        ajp_port => '8090',
        http_port => '8088',
    }   
}
node 'agent75.sunny.com'{
    $redismasterip = '172.18.50.72'
    $redismasterport = '6379'
    class{'redis::slave':
        masterip => "$redismasterip",
        masterport => "$redismasterport"
    }   
    include tomcat
}
import 'websvrs.d/*.pp'
import 'dbsvrs.d/*.pp'



2.2  例子



环境准备

服务器端安装puppet-server来实现server的角色

yum -y install puppet-server

安装server包后,对应目录/etc/puppet多了两个文件:fileserver.conf 和 manifests

在服务器端安装完成后,启动服务即可,不需要修改配置,默认监听端口是8140

systemctl restart puppetmaster.service

服务启动后,证书签署的目录 /var/lib/puppet/ssl会生成多个文件,这些文件是证书的相关文件

查看

ls  /var/lib/puppet/ssl

该目录下的文件,即使删除了,下次重启服务的时候就会重新生成,但是,注意,不要随意删除该目录下的文件,否则删除重启服务后之前签发的证书失效

如果要查看启动,清掉/var/lib/puppet/ssl文件后,执行如下命令可以看到  证书签发的相关过程,但是以下命令是非守护进程的方式启动,一般不这么启动,直接用systemctl启动服务即可

puppet master --no-daemonize -v -d --server master.sunny.com

客户端安装puppet包,充当agent端

yum -y install puppet

agent端要指定server,编辑配置文件,在main段加入如下的配置

  server = master.sunny.com

第一次启动

 puppet agent --no-daemonize -v -d --noop --test

此时不能成功启动,但是会生成一个证书请求文件发往服务器端,要等待服务器端签发证书

服务器端需要颁发证书

先查看

 puppet cert list

然后颁发

puppet cert sign agent72.sunny.com

服务器端颁发证书成功后,客户端再次启动,就可以成功启动

 puppet agent --no-daemonize -v -d  --test

注意,客户端可以执行如下命令进行启动

 systemctl restart puppetagent.service

准备,这里仅仅是测试,没有搭建dns,编辑所有的主机的hosts,如下

172.18.50.73   master.sunny.com
172.18.50.72   agent72.sunny.com
172.18.50.75   agent75.sunny.com
172.18.50.63   agent63.sunny.com
172.18.50.65   agent65.sunny.com

这里利用ansible工具将如上的语句重定向到每台机器的/etc/hosts文件里。将以上语句写入文件/root/host1里

执行如下命令

ansible all -m copy -a "dest=/root/host1 src=/root/host1"
ansible all -m shell -a "cat /root/host1 >> /etc/hosts"

完成所有hosts文件增加这5台服务器的解析

例1  配置redis主从服务器

agent72为redis 主服务器

agent75位redis从服务器

服务器端要有文件/etc/puppet/manifests/site.pp,声明对应主机使用的类

主节点编辑如下

vim /etc/puppet/manifests/site.pp
node 'agent72.sunny.com' {
    include redis::master
}
node 'agent75.sunny.com'{
    $redismasterip = '172.18.50.72'
    $redismasterport = '6379'
    class {'redis::slave':
        masterip => "$redismasterip",
        masterport => "$redismasterport"
    }   
}

从服务器上准备redis的模块,方法参加上文的例子:开发redis模块

注意,准备的文件需要有其他人读的权限,否则客户端来获取配置文件的时候会报错,没有权限

chmod  644 /etc/puppet/modules/redis/files/redis-master.conf
chmod  644  /etc/puppet/modules/redis/templates/redis-slave.conf.erb

redis模块目录机构如下

[root@master modules]#tree

.

└── redis

    ├── files

    │   └── redis-master.conf

    ├── lib

    ├── manifests

    │   ├── init.pp

    │   ├── master.pp

    │   └── slave.pp

    ├── spec

    ├── templates

    │   └── redis-slave.conf.erb

    └── tests

模块准备完成后,master上配置就完成了

agent服务器启动

systemctl  restart puppetagent.service

启动后,默认重启后会自动跟主服务器对比配置,如果和主服务器上定义的状态不一致,就会根据主服务器上site.pp的定义来配置本机。之后默认是每隔30分钟自动同步一次主服务器上的配置

注意第一次启动是,默认agent签署证书需要管理员手动在服务器端签发

测试

重启agent72和agent75两台服务器,如果redis都成功被安装,且实现了主从,则实验完成

如果重启不成功,建议通过命令puppet agent   --no-daemonize -v --noop查看启动服务过程的信息,可以加-d查看更加详细的过程,方便排错

例2  安装tomcat主机

主服务器上

先开发一个模块

1 创建目录

mkdir -pv /etc/puppet/modules/tomcat/{manifests,files,templates}

2 准备配置文件

获取配置文件进行修改,可以找一台机器安装tomcat后生成相关配置再拷贝到对应目录下

cp /etc/tomcat/server.xml /etc/puppet/modules/tomcat/templates/server.xml.erb
cp /etc/tomcat/tomcat-users.xml /etc/puppet/modules/tomcat/files/tomcat-users.xml
chmod 644  /etc/puppet/modules/tomcat/templates/server.xml.erb
chmod 644 /etc/puppet/modules/tomcat/files/tomcat-users.xml

这里的配置模板主要修改了如下的内容

vim /etc/puppet/modules/tomcat/templates/server.xml.erb
<Connector port="<%= @http_port %>" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
 <Connector port="<%= @ajp_port %>" protocol="AJP/1.3" redirectPort="8443" />
vim  /etc/puppet/modules/tomcat/files/tomcat-users.xml
<role rolename="admin-gui"/>
 <role rolename="manager-gui"/>
 <user username="tomcat" password="Pass1234" roles="manager-gui,admin-gui"/>

3.定义类,安装相关包和拷贝文件

vim /etc/puppet/modules/tomcat/mainfests/init.pp
class tomcat($http_port='8080',$ajp_port='8009'){
    package{['tomcat','tomcat-webapps','tomcat-admin-webapps', 'tomcat-docs-webapp']:
            ensure => latest,
    } ->
    file{'/etc/tomcat/server.xml':
            ensure => file,
            content => template('tomcat/server.xml.erb'),
            owner => 'root',
            group => 'tomcat',
            mode => '0644',
    }   
    file{'/etc/tomcat/tomcat-users.xml':
        ensure => file,
        source => 'puppet:///modules/tomcat/tomcat-users.xml',
        owner => 'root',
        group => 'tomcat',
        mode => '0640',
        require => Package['tomcat'],
    }   
    service{'tomcat':
        ensure => running,
        enable => true,
        subscribe => [File['/etc/tomcat/server.xml'],File['/etc/tomcat/tomcat-users.xml']],
    }   
}

#在site.pp里定义的变量优先级比init.pp里高

vim /etc/puppet/manifests/site.pp
node 'agent72.sunny.com' {
     class{'tomcat':
        ajp_port => '8090',
        http_port => '8088',
    }   
}
node 'agent75.sunny.com'{
    include tomcat
}

重启服务

master端

systemctl restart  puppetmaster

agent端

systemctl restart puppetagent

此时主服务器已经配置完成

从服务器最长30分钟后同步,这里通过重启agent服务直接激活

如果重启不成功,建议通过命令puppet agent   --no-daemonize -v --noop查看启动服务过程的信息,可以加-d查看更加详细的过程,方便排错


3  多环境配置


3.1 概念介绍


模块指明了要复用的代码,站点清单指明了哪些主机要用对应的代码。puppet默认是production(生产环境),要使用多环境,不一样的环境具有不一样的站点清单。

环境变量environmentpath默认是不存在的,查看变量命令如下

puppet config print environmentpath

puppet 3.4 之前的版本配置多环境的方法: 

各环境配置:以下每一个子目录表示一种环境

/etc/puppet/environments/{production,development,testing}

master支持多环境:puppet.conf

[master]
# modulepath=
# manifest=
environments = production, development, testing
[production]
modulepath=/etc/puppet/environments/production/modules/
manifest=/etc/puppet/environments/production/manifests/site.pp
[development]
modulepath=/etc/puppet/environments/development/modules/
manifest=/etc/puppet/environments/development/manifests/site.pp
[testing]
modulepath=/etc/puppet/environments/testing/modules/
manifest=/etc/puppet/environments/testing/manifests/site.pp

puppet 3.6(包含3.6)之后的版本配置多环境的方法:

master支持多环境:

(1) 配置文件puppet.conf

[master]
environmentpath = $confdir/environments

$confdir一般指/etc/puppet这个目录

(2) 在多环境配置目录下为每个环境准备一个子目录

ENVIRONMENT_NAME/

manifests/

site.pp

modules/

额外配置文件:

文件系统:fileserver.conf,默认配置可用,不需要调整

认证(URL):auth.conf:在该文件中,method为find表示读请求,method为save为其他请求,默认没有指定任何操作,则默认表示拒绝所有,如最后的path /

查看master端日志

master端和agent的通信日志如下文件

/var/log/puppet/masterhttp.log

查看每台主机对应在服务器端操作的报告,见如下路径的文档。

/var/lib/puppet/reports/

该目录下会生成以主机名为目录的文件,在对应主机下一yaml格式记录各个文件

puppet kick:紧急修复的时候会用到这个功能

默认agent是周期性来获取配置的,那么可以考虑用服务器端推送请求来通知agent的方式,告知agent,使得agent可以及时同步新的配置文件

master端执行如下格式:

puppet kick [--host <HOST>] [--all]

agent端要监听在某一套接字上才能实现kick功能,默认端口是8139


3.2  例子 



例1  不同环境下安装memcached

准备不同环境(testing,development,production)的目录

mkdir -pv /etc/puppet/environments/{development,production,testing}/manifests
mkdir -pv /etc/puppet/environments/{development,production,testing}/modules/memcached/{manifests,files,templates}

服务器端配置如下

#新增一个配置端master

vim /etc/puppet/puppet.conf
[master]
    environmentpath = $confdir/environments

查看特定段变量,如master段,如section端的变量,否则默认没有section变量,查看的是main段的配置

puppet config print environmentpath --section master

准备配置模板文件

注意,配置文件中,不同环境下,内存大小不一样,内存大小的值通过参数来传递

准备redis模块

#testing环境

vim /etc/puppet/environments/testing/modules/memcached/manifests/init.pp
class memcached($maxmemory='64'){
    package{'memcached':
        ensure => latest,
        provider => yum,
    }   
    file{'/etc/sysconfig/memcached':
        ensure => file,
        content => template('memcached/memcached.erb'),
        owner => 'root',
        group => 'root',
        mode => '0644',
    }   
    service{'memcached':
        ensure => running,
        enable => true,
    }   
   Package['memcached'] -> File['/etc/sysconfig/memcached'] ~>Service['memcached']
}

#development环境

vim /etc/puppet/environments/development/modules/memcached/manifests/init.pp
class memcached($maxmemory='128'){
    package{'memcached':
        ensure => latest,
        provider => yum,
    }   
    file{'/etc/sysconfig/memcached':
        ensure => file,
        content => template('memcached/memcached.erb'),
        owner => 'root',
        group => 'root',
        mode => '0644',
    }   
    service{'memcached':
        ensure => running,
        enable => true,
    }   
   Package['memcached'] -> File['/etc/sysconfig/memcached'] ~>Service['memcached']
}

production环境

vim /etc/puppet/environments/production/modules/memcached/manifests/init.pp
class memcached($maxmemory='256'){
    package{'memcached':
        ensure => latest,
        provider => yum,
    }   
    file{'/etc/sysconfig/memcached':
        ensure => file,
        content => template('memcached/memcached.erb'),
        owner => 'root',
        group => 'root',
        mode => '0644',
    }   
    service{'memcached':
        ensure => running,
        enable => true,
    }   
   Package['memcached'] -> File['/etc/sysconfig/memcached'] ~>Service['memcached']
}

准备memcached配置模板文件

vim  /etc/puppet/environments/production/modules/memcached/templates/memcached.erb 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="<%= @maxmemory %>" 
OPTIONS=""

把该模板复制到其他两个环境下

在不同环境下定义site.pp

vim  /etc/puppet/environments/production/manifests/site.pp
node 'agent72.sunny.com'{
    class {'memcached':
        maxmemory => '512',
    
    }   
}
vim  /etc/puppet/environments/testing/manifests/site.pp  
node 'agent72.sunny.com'{
    include memcached
}
 vim  /etc/puppet/environments/production/manifests/site.pp  
node 'agent72.sunny.com'{
    include memcached
}


到这里,master上环境准备完成

此时各个环境的目录树结构如下

[root@master ~]#tree /etc/puppet/environments/

/etc/puppet/environments/

├── common

├── development

│   ├── manifests

│   │   └── site.pp

│   └── modules

│       └── memcached

│           ├── files

│           ├── manifests

│           │   └── init.pp

│           └── templates

│               └── memcached.erb

├── production

│   ├── manifests

│   │   └── site.pp

│   └── modules

│       └── memcached

│           ├── files

│           ├── manifests

│           │   └── init.pp

│           └── templates

│               └── memcached.erb

└── testing

    ├── manifests

    │   └── site.pp

    └── modules

        └── memcached

            ├── files

            ├── manifests

            │   └── init.pp

            └── templates

                └── memcached.erb


22 directories, 9 files

该实验建议在其他目录先准备模块,完成后,再将准备好的模块放在到对应环境下的模块里

cp -r /root/memcached /etc/puppet/environments/testing/modules
cp -r /root/memcached /etc/puppet/environments/production/modules
cp -r /root/memcached /etc/puppet/environments/development/modules

测试

服务器端重启服务

systemctl restart puppetmaster

agent72端

查看当前环境

puppet config print environment

每一站点拥有所有的环境拥有不同的站点资源,手动指定不同的环境进行安装,安装后的memcached的内存大小不一样

#开发

puppet agent --no-daemonize -v --environment=development

#生产环境

puppet agent --no-daemonize -v --environment=production

#测试环境

puppet agent --no-daemonize -v --environment=testing

在实际环境中,每台主机对应的环境是确定的,可以将环境配置在配置文件里

agent端:

[agent]

environment = { production|development | testing }

例子,在配置文件agent里指定当前机器为testing环境

vim /etc/puppet/puppet.conf
[agent]
environment = testing

配置更改完成后,重启agent服务,会自动匹配master定义的状态

systemctl restart puppetagent

到这里该例子完成

例2  kick 命令使用

agent端修改配置文件

vim /etc/puppet/puppet.conf
puppet.conf
[agent]
listen = true
vim /etc/puppet/auth.conf
path /run
method save 
auth any 
allow  master.sunny.com  #这里指明master的服务器地址

重启服务,agent会监听8139端口

systemctl restart puppetagent

服务器端配置

定义模块,安装nginx并启动nginx服务

 mkdir -pv   /etc/puppet/environments/testing/modules/nginx/{manifests,files,templates}
 vim  /etc/puppet/environments/testing/modules/nginx/manifests/init.pp
class nginx {
    package{'nginx':
        ensure => latest,
     } ->
     service{'nginx':
        ensure => running,
     }   
}


vim /etc/puppet/environments/testing/manifests/site.pp
node 'agent72.sunny.com'{
    include nginx
}

到这里,新的模块已经添加完成

测试

服务器端执行

puppet kick agent72.sunny.com

在agent72.sunny.com上验证,如果已经成功安装nginx服务包,且能够启动nginx服务,则实验成功