本文最后更新于 2020 年 3 月 13 日,文章已超过 6 个月!内容可能已失效,请自行测试 ~

简介

随着各种业务对IT服务的依赖器重,企业IT基础架构,规模不断扩张。作为一名系统工程师我们将如何应对这种日益增长的IT架构呢?以前系统工程师就像流水线上的工人,不断重复做着同样工作,现在这一切即将改变,我们将引入运维自动化工具puppet。本章首先介绍puppet的工作原理,然后介绍puppet的部署与应用。

1.案例概述
作为一名系统管理员,维护服务器正常运行是最基本的职责,在管理几台到几十台服务器时,大部分系统管理员喜欢写自己的小工具来维护,但是随着服务器数量的增多,任务量也逐渐增加,这时就需要简洁的,强大的框架来完成系统管理任务。

2.案例前置知识点
puppet工作原理如下。
puppet的目的是让管理员只集中于要管理的目标,而忽略实现的细节。puppet既可以在单个机器上使用,也可以C/S结构使用。在大规模使用puppet的情况下,通常使用C/S结构,在这种结构中puppet客户端之运行puppetclient,puppet服务器端只运行puppetmaster。

具体的工作流程如图12.1所示
(1)客户端puppet调用facter(facter是通过ssl加密收集及检测分析客户端配置信息的一个工具),facter探测出主机的一些变量,如主机名、内存大小、ip地址等。puppet把这些信息通过ssl连接发送到服务器端。
(2)服务器端的puppetmaster通过facter工具分析检测客户端的主机名,然后找到项目主配置文件manifest里对应的node配置,并对部分内容进行解析。facter发送过来的信息可以作为变量处理,node牵涉到的代码才解析,其他没牵涉到的代码不解析。解析分为几个阶段,首先进行语法检查,如语法没错,就继续解析,解析的结果生成一个中间的“伪代码”,然后把伪代码发送到客户端。
(3)客户端收到“伪代码”并且执行,客户端把执行结果发送给服务器。
(4)服务器端把客户端的执行结果写入日志。

puppet工作过程中有以下两个点值得注意。
(1)为了保证安全,client和master之间是基于ssl和证书的,只有经master证书认证的client可以与master通信。
(2)puppet会让系统保持在人们所期望的某种状态并一直维持下去,如检测到某个文件并保证其一直存在,保证ssh服务始终开启,如果文件被删除了或者ssh服务被关闭了,puppet下次执行时(默认30分钟),会重新创建该文件或者启动ssh服务。

1.搭建时间同步服务器
由于facter使用SSL证书,依赖时间同步,所有需要搭建NTP服务器

1)搭建NTP Server

[root@RHEL6-Server4 ~]# yum -y install ntp
[root@RHEL6-Server4 ~]# vim /etc/ntp.conf
server 127.127.1.0
fudge 127.127.1.0 stratum 8	

当/etc/ntp.conf文件中的server都不可用时,使用local时间作为NTP server 提供给 client

[root@RHEL6-Server4 ~]# service ntpd start                                            
[root@RHEL6-Server4 ~]# chkconfig ntpd on

2.搭建 puppetmaster
1)规划服务器主机名
在小规模puppet环境下,修改/etc/hosts文件,在上千台服务器环境下,需要自己搭建DNS服务器来保证服务器直接通过主机名通信。

[root@RHEL6-Server1 ~]# vim /etc/sysconfig/network
HOSTNAME=master.test.cn
[root@RHEL6-Server1 ~]# hostname master.test.cn
[root@RHEL6-Server1 ~]# bash
[root@master ~]# vim /etc/hosts
192.168.200.211 master.test.cn
192.168.200.212 client1.test.cn
192.168.200.213 client2.test.cn

2)puppetmaster 作为NTP客户端的配置

[root@master ~]# yum -y install ntpdate
[root@master ~]# ntpdate 192.168.200.214

3)安装ruby
先安装compat-readline5

[root@master ~]# mount /dev/cdrom /media/cdrom/
[root@master ~]# rpm -ivh /media/cdrom/Packages/compat-readline5-5.2-17.1.el6.x86_64.rpm	 
[root@master ~]# rpm -ivh ruby-*

检查ruby的版本

[root@master ~]# ruby -v
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

4)安装puppet facter

[root@master ~]# useradd  -s /sbin/nologin puppet

通过facter工具分析检测客户端传输过来的信息
a) 安装facter:

[root@master ~]# tar xf facter-1.7.1.tar.gz 
[root@master ~]# cd facter-1.7.1
[root@master facter-1.7.1]# ruby install.rb

b) 安装puppet:

[root@master ~]# tar xf puppet-2.7.21.tar.gz 
[root@master ~]# cd puppet-2.7.21
[root@master puppet-2.7.21]# ruby install.rb 

c) 复制配置文件

[root@master puppet-2.7.21]# cp conf/redhat/fileserver.conf /etc/puppet/
[root@master puppet-2.7.21]# cp conf/redhat/puppet.conf /etc/puppet/
[root@master puppet-2.7.21]# cp conf/redhat/server.init /etc/init.d/puppetmaster

d) 修改文件属性

[root@master puppet-2.7.21]# chmod +x /etc/init.d/puppetmaster

e) 创建puppet主目录

[root@master ~]# mkdir /etc/puppet/manifests
[root@master ~]# mkdir /etc/puppet/modules

f) puppet服务证书请求与签名
生产环境中iptables默认都是全部关闭的
master端配置:

[root@master ~]# service iptables stop

g) 修改配置文件:配置服务器模块路径 在main标题下

[root@master ~]# vim /etc/puppet/puppet.conf 
 13     modulepath = /etc/puppet/modules:/usr/share/puppet/modules

h) 启动puppet主程序

[root@master ~]# /etc/init.d/puppetmaster start
启动 puppetmaster:                                        [确定]

3.搭建puppetclient
配置puppetclient1
1)规划服务器主机名

[root@RHEL6-Server2 ~]# vim /etc/sysconfig/network
HOSTNAME=client1.test.cn
[root@RHEL6-Server2 ~]# hostname client1.test.cn
[root@RHEL6-Server2 ~]# bash
[root@client1 ~]# vim /etc/hosts
192.168.200.211 master.test.cn
192.168.200.212 client1.test.cn
192.168.200.213 client2.test.cn

确保通过主机与master通信

[root@client1 ~]# ping master.test.cn
PING master.test.cn (192.168.200.211) 56(84) bytes of data.
64 bytes from master.test.cn (192.168.200.211): icmp_seq=1 ttl=64 time=0.509 ms

2)服务器时间同步

[root@client1 ~]# yum -y install ntpdate   
[root@client1 ~]# ntpdate 192.168.200.214

3)安装ruby
先安装compat-readline5

[root@client1 ~]# mount /dev/cdrom /media/cdrom/
[root@client1 ~]# rpm -ivh /media/cdrom/Packages/compat-readline5-5.2-17.1.el6.x86_64.rpm  
[root@client1 ~]# rpm -ivh ruby-*

检查ruby的版本

[root@client1 ~]# ruby -v
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

4)安装puppet facter

[root@client1 ~]# useradd  -s /sbin/nologin puppet

通过facter工具分析检测客户端传输过来的信息
a) 安装facter:

[root@client1 ~]# tar xf facter-1.7.1.tar.gz 
[root@client1 ~]# cd facter-1.7.1
[root@client1 facter-1.7.1]# ruby install.rb

b) 安装puppet:

[root@client1 ~]# tar xf puppet-2.7.21.tar.gz 
[root@client1 ~]# cd puppet-2.7.21
[root@client1 puppet-2.7.21]# ruby install.rb

c) 复制配置文件

[root@client1 puppet-2.7.21]# cp conf/redhat/puppet.conf /etc/puppet/
[root@client1 puppet-2.7.21]# cp conf/redhat/client.init /etc/init.d/puppetclient

d) 修改文件属性

[root@client1 puppet-2.7.21]# chmod +x /etc/init.d/puppetclient

e) puppet服务证书请求与签名
生产环境中iptables默认都是全部关闭的
master端配置:

[root@client1 puppet-2.7.21]# service iptables stop

f) 修改配置文件:配置服务器的域名 在main标题下

[root@client1 ~]# vim /etc/puppet/puppet.conf 
 13     server = master.test.cn

puppetclient1 与 puppetclient2 配置基本一致,注意主机名

g)申请与注册
puppetclient1 与 puppetclient2 上进行注册

[root@client1 ~]# puppet agent --server=master.test.cn --no-daemonize --verbose
info: Creating a new SSL key for client2.test.cn
info: Caching certificate for ca
info: Creating a new SSL certificate request for client2.test.cn
info: Certificate Request fingerprint (md5): D8:FF:EC:D9:F8:58:52:69:21:07:3C:7A:05:D3:BB:AF

此时可以按Ctrl+C,因为puppet一直等待任务

master端:查看申请注册的客户端:

[root@master ~]# puppet cert --list
  "client1.test.cn" (B8:30:C5:19:4F:15:0F:D6:49:27:88:D6:0C:36:8F:EB)
  "client2.test.cn" (D8:FF:EC:D9:F8:58:52:69:21:07:3C:7A:05:D3:BB:AF)

将未注册的客户端进行注册:

[root@master ~]# puppet cert sign --all
notice: Signed certificate request for client2.test.cn
notice: Removing file Puppet::SSL::CertificateRequest client2.test.cn at '/var/lib/puppet/ssl/ca/requests/client2.test.cn.pem'
notice: Signed certificate request for client1.test.cn
notice: Removing file Puppet::SSL::CertificateRequest client1.test.cn at '/var/lib/puppet/ssl/ca/requests/client1.test.cn.pem'

通过目录去查看已经注册的客户端:

[root@master ~]# ll /var/lib/puppet/ssl/ca/signed/
总用量 12
-rw-r----- 1 puppet puppet 1911 10月 21 17:57 client1.test.cn.pem
-rw-r----- 1 puppet puppet 1911 10月 21 17:57 client2.test.cn.pem
-rw-r----- 1 puppet puppet 1976 10月 21 17:25 master.test.cn.pem

客户端已经完成证书的申请与签名;

4.配置实例
4.1 配置一个测试节点
节点信息:/etc/puppet/manifests/nodes
模块信息:/etc/puppet/modules

为了保护Linux的ssh端口爆破,批量修改客户端sshd端口,将端口22修改为9922并实现重启工作。

创建ssh模块,模块目录为ssh,模块下面有三个文件:manifests,templates和files。

manifests里面必须要包含一个init.pp的文件,这是该模块的初始(入口)文件,导入一个模块的时候,会从init.pp开始开始执行。可以把所有的代码都写到init.pp里面,也可以分成多个pp文件,init再去包含其他文件,定义class类名的时候必须是ssh,这样能实现调用。

files 目录是该模块的文件发布目录,puppet提供一个文件分发机制,类似于rsync的模块

templates目录包含erb模型文件,这个和files资源的template属性有关(很少用)

master端:
1)创建需要的必要目录。

[root@master ~]# mkdir -p /etc/puppet/modules/ssh/{manifests,templates,files}
[root@master ~]# mkdir /etc/puppet/manifests/nodes
[root@master ~]# mkdir /etc/puppet/modules/ssh/files/ssh
[root@master ~]# chown -R puppet /etc/puppet/modules/
[root@master ~]# ls -l /etc/puppet/modules/ssh/
总用量 12
drwxr-xr-x 3 puppet root 4096 10月 21 18:05 files
drwxr-xr-x 2 puppet root 4096 10月 21 18:05 manifests
drwxr-xr-x 2 puppet root 4096 10月 21 18:04 templates

2)创建模块配置文件install.pp(首先确定客户端安装ssh服务)

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/install.pp
class ssh::install{
	package{ "openssh":
		ensure => present,
	}
}

3)创建模块配置文件config.pp (配置需要同步的文件)

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/config.pp
class ssh::config {
        file { "/etc/ssh/sshd_config":												//配置客户端需要同步的文件
                ensure => present,													//确定客户端此文件存在
                owner => "root", 
                group => "root",
                mode => "0600",
                source => "puppet://$puppetserver/modules/ssh/ssh/sshd_config",   	//从服务器端同步文件  $puppetserver 指定 /etc/puppet 文件
                require => Class["ssh::install"],      								//调用install.pp确定ssh已经安装
                notify => Class["ssh::service"],									//如果config.pp发生变化通知service.pp
        }
}

4)创建模块配置文件service.pp

[root@master ~]# vim /etc/puppet/modules/ssh/manifests/service.pp
class ssh::service {
        service { "sshd":   						//确定ssh运行
                ensure => running,					
                hasstatus => true,					//puppet该服务支持status命令,类似service sshd status
                hasrestart => true,					//puppet该服务支持restart命令,类似service sshd restart
                enable => true,  					//服务器是否开机启动
                require => Class["ssh::config"]  	//确认config.pp调用
        }
}

class ssh::service {
        service { "sshd":   						
                ensure => running,					
                hasstatus => true,					
                hasrestart => true,					
                enable => true,  					
                require => Class["ssh::config"]  	
        }
}

5)创建模块配置文件init.pp

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

[root@master ~]# ll /etc/puppet/modules/ssh/manifests/
总用量 16
-rw-r--r-- 1 root root 254 10月 21 18:16 config.pp
-rw-r--r-- 1 root root  60 10月 21 18:23 init.pp
-rw-r--r-- 1 root root  65 10月 21 18:09 install.pp
-rw-r--r-- 1 root root 148 10月 21 18:19 service.pp

6)建立服务器端 ssh 统一维护文件
由于服务器端和客户端sshd_config 文件默认一样,将服务端配置文件复制到模块默认路径

[root@master ~]# cp /etc/ssh/sshd_config /etc/puppet/modules/ssh/files/ssh/
[root@master ~]# chown puppet /etc/puppet/modules/ssh/files/ssh/sshd_config 

7)创建测试节点配置文件,并将ssh加载进去

[root@master ~]# vim /etc/puppet/manifests/nodes/ssh.pp
node 'client1.test.cn' {
        include ssh
}
node 'client2.test.cn' {
        include ssh
}

8) 将测试节点载入puppet,即修改site.pp

[root@master ~]# vim /etc/puppet/manifests/site.pp
import "nodes/ssh.pp"

9) 修改服务器端维护的sshd_config配置文件

[root@master ~]# vim /etc/puppet/modules/ssh/files/ssh/sshd_config
Port 9922

10)重启puppet

[root@master ~]# /etc/init.d/puppetmaster restart
停止 puppetmaster:                                        [确定]
启动 puppetmaster:                                        [确定]

4.2 客户端主动拉取
一般在小规模自动化集群中,如代码上线需重启服务时,为了防止网站暂时性无法访问的问题,每台客户端运行一次puppet agent -t命令,选择模式根据客户端集群规模大小,根据经验,一般运维工程师puppet服务器到客户端会建立ssh信任,然后自定义shell脚本,ssh批量让客户端执行puppet同步命令。

Client端:192.168.200.212 端执行命令如下:

[root@client2 ~]# puppet agent -t
info: Caching catalog for client2.test.cn
info: Applying configuration version '1445426326'
notice: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]/content: 
--- /etc/ssh/sshd_config	2015-08-08 16:39:36.986999633 +0800
+++ /tmp/puppet-file20151022-57210-s37jl6-0	2015-10-22 19:24:28.555648885 +0800
@@ -10,7 +10,7 @@
 # possible, but leave them commented.  Uncommented options change a
 # default value.
 
-Port 22
+Port 9922
 #AddressFamily any
 #ListenAddress 0.0.0.0
 #ListenAddress ::

info: FileBucket adding {md5}00d0f172a955e42dcb9dc5074afee3e8
info: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]: Filebucketed /etc/ssh/sshd_config to puppet with sum 00d0f172a955e42dcb9dc5074afee3e8
notice: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]/content: content changed '{md5}00d0f172a955e42dcb9dc5074afee3e8' to '{md5}470d359ae263214d5319f2c8ef4014ae'
info: /Stage[main]/Ssh::Config/File[/etc/ssh/sshd_config]: Scheduling refresh of Class[Ssh::Service]
info: Class[Ssh::Service]: Scheduling refresh of Service[sshd]
notice: /Stage[main]/Ssh::Service/Service[sshd]: Triggered 'refresh' from 1 events
info: Creating state file /var/lib/puppet/state/state.yaml
notice: Finished catalog run in 3.75 seconds

此时,在客户端已经成功执行。验证如下

[root@client1 ~]# grep "9922" /etc/ssh/sshd_config 
Port 9922

查看服务器ssh服务重启,端口是否生效

[root@client1 ~]# netstat -anpt | grep sshd     
tcp        0      0 0.0.0.0:9922                0.0.0.0:*                   LISTEN      61132/sshd          
tcp        0     52 192.168.200.212:22          192.168.200.1:64178         ESTABLISHED 57619/sshd                 
tcp        0      0 :::9922                     :::*                        LISTEN      61132/sshd 

4.3 服务器推送同步
当大规模部署时采用服务器推送模式。
Client端:192.168.200.212端修改
1) 修改配置文件:

[root@client1 ~]# vi /etc/puppet/puppet.conf  	最后添加一行如下:
listen = true  //使puppet监听8139端口
[root@client1 ~]# vi /etc/puppet/auth.conf  //验证配置文件auth.conf定义一些验证信息及访问权限,最后一行添加如下:
allow *  //允许任何服务器端推送

启动puppet客户端

[root@client1 ~]# sed -n '11,15p' /etc/ssh/sshd_config 
# default value.

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
[root@client1 ~]# /etc/init.d/puppetclient start
启动 puppet:                                              [确定]

稍等一会儿再去查看

[root@client1 ~]# sed -n '11,15p' /etc/ssh/sshd_config 
# default value.

Port 9922
#AddressFamily any
#ListenAddress 0.0.0.0

Master端也可以强制推送

[root@master ~]# puppet kick client1.test.cn
Triggering client1.test.cn
Getting status
status is success
client1.test.cn finished with exit code 0
Finished

该文章采用「CC 协议」,转载必须注明作者和本文链接.
分类: Linux