您的位置:首页 > 运维架构

运维自动化管理工具之Puppet

2017-01-07 15:34 585 查看
一、相关概念

1、puppet是什么?
a、开源的集中式配置管理工具。通过自有配置语言对节点进行目标状态定义,并能够基于网络实现目标状态的维护。
b、采用C/S架构即master和agent,master作为中心配置库,agent用来读取并应用配置的节点。
c、puppet定义目标状态的核心组件:"资源",
d、发行版本: 0.24,0.25,2.6,2.7(巨大变化),3.x(基于2.7为原型)
e、管理目标:众多linux发行版本,windows等几乎所有操作系统。

2、puppet认证方式是什么?
puppet的master与agent是基于ssl认证,而证书的颁布依赖于使用主机的主机名。(好处:ip变了,主机名没变那么证书还依然能用),因此master需要可以解析所有agent的主机名。

3、master与agent是怎么通讯的?
通讯基于https的XMLRPC协议进行的,master不会主动发起对agent的请求,而是客户端每个固定时长(默认半个小时)去服务器端查找是否有关于本节点的配置信息,如果有master就将配置模板发给agent,然后agent读到后,就根据模板进行操作了。

4、puppet的工作原理(重点理解部分):
宏观理解工作原理:要想使某台主机到达某目标状态需要每隔一段时间去master查找配置文件,这个配置文件定义了需要安装哪些模块,而模块组织了所有的依赖关系,agent拿到配置需求进行执行,然后将结果返回给master,master将结果保存到databases中,这些结果可以用通过puppet dashboard或foreman来进行展示。

微观:define -> 模拟 -> 强制 -> REPORT, 即(define) 在master端定义了资源信息 (模拟)agent读到这些信息后不会立即执行而是先模拟执行一次,如果成功,(强制)则执行这些变更,最后(report)报告自己的工作状态。

master与agent信息交互细节:agent通过factor将执行结果(主机名,ip等)发给master,master会根据agent的情况来选择一些清单manifest然后,将其进行编译成伪代码catalog,然后交给agent,agent在进行上边所述的"模拟"->"报告"的工作。

二、puppet安装

#puppet(2.7比较流行的稳定版本)
1、下载地址:
https://yum.puppetlabs.com/el/6.5/products/x86_64/puppet-2.7.25-1.el6.noarch.rpm https://yum.puppetlabs.com/el/6.5/products/x86_64/facter-1.7.6-1.el6.x86_64.rpm[/code]2、使用模型: 
a、单机使用
安装puppet
b、master/agent
master:puppet,puppet-server
agent:puppet
3、安装:
安装部分比较简单,也不是本文介绍的重点所以这里就不多介绍了,我这里采用rpm安装。
rpm -ivh xxxx.rpm


三、puppet详解
1、定义资源:
资源是以.pp结尾的。
格式:
type {"title":
v1 => k1,
v2 => k2,
}
说明:
1、在定义资源时候,资源类型必须使用字符串;
2、同一个类型中其必须唯一 比如:package app1 与 service app1可以,都是package则不行。
[root@l-mem-test2 tmp]# cat test.pp
notify{'notice':
message => 'welcome to puppet.',
}
[root@l-mem-test2 tmp]# puppet apply test.pp    ## 应用这个puppet
notice: welcome to puppet.
notice: /Stage[main]//Notify[notice]/message: defined 'message' as 'welcome to puppet.'
notice: Finished catalog run in 0.02 seconds
[root@l-mem-test2 tmp]# puppet apply test.pp -v    ## 详细的信息 包括版本号
info: Applying configuration version '1483548877'
notice: welcome to puppet.
notice: /Stage[main]//Notify[notice]/message: defined 'message' as 'welcome to puppet.'
notice: Finished catalog run in 0.05 seconds
[root@l-mem-test2 tmp]# puppet apply test.pp -v     ## 你会发现及时没变更版本号也会变更
info: Applying configuration version '1483548887'
notice: welcome to puppet.
notice: /Stage[main]//Notify[notice]/message: defined 'message' as 'welcome to puppet.'
notice: Finished catalog run in 0.05 seconds


2、核心资源:notify、package、user、group、file、exec,cron、service

notify通知,用于调试输出:

常用参数:
message:要输出什么信息
name:名称

package(管理软件包):
常用属性:
ensure:程序包的目标状态;
name:资源的名称,即软件包的名字;
provider:软件包管理器(yum,rpm,apt,ports,gem,msi,dpkg,pkg)
source:指定程序包文件路径
install_options:指定安装选项 最常用的通过INSTALLDIR来指定安装目录

例如windows下安装mysql
package {'mysql':
ensure => installed,
provider => 'msi',
source => 'D:\software\mysql-5.5.36.msi',
install_options => {'INSTALLDIR' => 'C:\mysql'},
}

service(管理服务):
常用属性:
ensure:服务目标状态,true和false
enable:是否开机自启动,true和false
name:服务名称
path:服务脚本路径(如果不写默认到/etc/init.d/找name相同的脚本);
start:订制启动命令
stop:停止命令
restart:订制重启命令
status:状态信息获取命令

file(管理文件、目录、符号连接、生成文件内容、管理文件权限、管理文件属性、通过source属性到制定位置下载文件、通过recurse属性来获取整个目录)
常用属性:
ensure:目标状态present,absent,file,directory
backup:通过filebucket资源来备份文件;对应值通常问filebucket资源名称;
content:文件内容,生成方式有三种(content,source,target),这三种互斥仅能使用一种;
source:通过指定的url下载文件至本地;获取方式通常为puppet url,格式puppet:///modules/MODULES_NAME/file_names;
target:为符号链接指定目标;
links:文件为符号链接(follow|manage);
path:文件路径,注意必须使用双引号;
mode:定义权限;
owner:属主;
group:属组;
force:强制执行删除文件、连接、或目录,因此该属性仅用于ensure为absent时;
purge:清空指定目录中存在,但未在资源中定义的文件;
recurse:用于目录递归,值true,false,inf,remote
replace:替换;如果本地存在的文件与资源中指定的文件内容不同时是否执行替换,默认为否;
#####示例:
[root@l-mem-test2 tmp]# cat test3.pp
file {'abc4.txt':
ensure  => present,
content => "hello puppet",
path    => "/tmp/abc4.txt",
}
file {'fstab.symbolic':
ensure  => present,
target  => "/etc/fstab",
path    => "/tmp/fstab.symbolic",
links  => follow,
}
[root@l-mem-test2 tmp]# ls -l |grep fstab
lrwxrwxrwx. 1 root root   10 1月   5 18:27 fstab.symbolic -> /etc/fstab


exec(执行命令,通常在不得不用时才使用,通常用于完成puppet自身无法完成的功能):
常用属性:
command:要执行的命令,通常为命令的完成路径;
path:命令搜索路径;
group:以谁为属主执行;
user:以谁为属主执行;
onlyif:0,表示仅在命令状态返回值为0时才执行此命令;
refresh:接收到其他资源的通知时,重新执行此命令;
refreshonly:仅当被以来的资源发生改变时,才被触发;
tries:尝试次数,默认为1;
try_sleep;尝试次数大于1时的时间间隔;

####示例:
[root@l-mem-test2 tmp]# cat test4.pp
exec {'echo command':
command => 'touch /tmp/tmp.xxx',
path    => '/bin:/sbin:/usr/bin:/usr/sbin'
}
[root@l-mem-test2 tmp]# puppet apply test4.pp
notice: /Stage[main]//Exec[echo command]/returns: executed successfully
notice: Finished catalog run in 0.09 seconds
[root@l-mem-test2 tmp]# ls |grep tmp
tmp.xxx


group管理系统上的用户组:
常用属性:
ensure:目标状态 present,absent
name:组名
gid:GID
system:系统组
###示例:
[root@l-mem-test2 tmp]# cat group.pp
group {'testgrp':
ensure => present,
gid    => 1001,
}
[root@l-mem-test2 tmp]# puppet apply group.pp
notice: /Stage[main]//Group[testgrp]/ensure: created
notice: Finished catalog run in 0.53 seconds
[root@l-mem-test2 tmp]# tail /etc/group|grep test
testgrp:x:1001:


user管理用户:
常用属性:
ensure:目标状态
uid:UID
name:用户名
system:是不是系统用户
home:家目录
shell:
gid:用户组id
password:密码(要是用加密后的密码串)
managehome:是否创建家目录 ture,false

###示例:
user {'testuser':
ensure  => present,
gid     => 1001,
uid     => 1001,
home    => '/home/test',
shell   => '/bin/tcsh',
password => '$1$25fb0f71$M3Ny.rWQjSy.mOcONDEO9.',
managehome => true,
}


cron定义周期性任务:
常用属性:
ensure:目标状态present absent
command:命令或脚本
environment:运行时的环境变量
hour
minute
month
monthday
weekday
name:名字
user:运行时的用户身份(默认为root)
###示例:
[root@l-mem-test2 tmp]# cat cron.pp
cron {'ntpdate':
ensure => present,
command => '/usr/sbin/ntpdate time.nist.gov',
minute => '*/3',### 每三分钟,只定义分钟,其他可以省略
}
[root@l-mem-test2 tmp]# crontab -l
# HEADER: This file was autogenerated at Fri Jan 06 00:15:11 +0800 2017 by puppet.
# HEADER: While it can still be managed manually, it is definitely not recommended.
# HEADER: Note particularly that the comments starting with 'Puppet Name' should
# HEADER: not be deleted, as doing so could cause duplicate cron jobs.
# Puppet Name: ntpdate
*/3 * * * * /usr/sbin/ntpdate time.nist.gov


3、元参数与资源引用
资源引用:
Type['title']  #type开通字母大写
例如:
Package['httpd']


属性中的特殊属性
1、name(都有,一般不写调用title)
2、ensure
3、元参数
用于定于资源间的依赖关系,及应用次序,通知机制;
require:
package {'nginx':
ensure => present,
}
service {'nginx':
ensure => true,
enable => true,
require => Package['nginx'],   ### 表示该服务依赖 package
}
## 另一种写法:
before
package {'nginx':
ensure => present,
before => Service['nginx']
}
service {'nginx':
ensure => true,
enable => true,
}


notify,subscribe 通知与订阅 同require和before一个意思 一个写在前面一个写在后面
[root@l-mem-test2 tmp]# cat test5.pp
file {'/tmp/tt.txt':
ensure => present,
content => "hello",
}
exec {'monitor':
command => 'echo "/tmp/tt.txt changed">>/tmp/monitor.txt',
subscribe => File['/tmp/tt.txt'],### 订阅了资源
refreshonly => true,## 检查文件改变时重新执行
path     => "/bin:/sbin:/usr/bin:/use/sbin/",## 给echo定义path路径
}


资源间的应用次序链
"->"用于定义次序链,而"~>"用于定于通知链
例如:nginx先安装软件包在操作nginx配置文件,当nginx配置文件改变时通知service服务启动
package{"nginx":ensure => present,} ->
file {'nginx.conf': ensure => present,} ~>
service {'nginx':
ensure => running,
enable => true,
}


4、puppet变量
a、puppet变量:
(1)、名称必须以“$”开头,赋值操作符为“=”
(2)、任何正常数据类型(非正则)的值都可以赋予puppet中的变量,如字符串、数值、布尔值、数组、hash以及特殊的undef值(即变量未被赋值)
(3)、puppet的每个变量都有2个名字,简短名称和长格式完全限定名称(FQN),完全限定名称格式为“$scope::variable”

b、puppet分为哪几种?
(1)、自定义变量
(2)、facter变量
(3)、内置变量:
agent:$environment、$clientcert、$clientversion
master:$serverip,$serverversion,$servername

c、puppet变量的数据类型:
1、字符型
非结构化的文本字符串,可以使用双引号,也可以不用;
单引号中的变量不会被替换,而双引号中的能够替换变量
字符型值也支持使用转移符 例如“\n”
2、数值型
可为整数或浮点数,不过puppet只有在数值上下文才能把数值当数值型对待,其他情况一律以字符串处理
3、数组
数组值为中括号"[]"中的以逗号分隔的项目列表,最后一个项目后面可以有逗号
数组中的元素可以为任意可用数据类型,包含hash或其他数组
数组索引为从0开始的整数,也可以使用负数索引。
4、布尔型
true和false,不能加引号
if语句的测试条件和比较表达式都会返回布尔型值
另外其他数据类型也可自动转换为布尔型,如空字符串为false等。
5、undef
未被声明的变量的值类型undef
也可以手动为某变量赋予undef,即直接使用不加引号的undef字符串。
6、hash
即为外键值数据类型,建和值之间使用“=>”分隔,建值对儿定义在“{}”中,彼此间以逗号分隔
其建为字符型数据,而值可以为puppet支持的任意数据类型
访问hash类型的数据元素要使用“键”当做索引进行
7、正则表达式
属于puppet的非标准数据类型,不能复制给变量,仅能用于有限的几个接受正则表达式的地方,即接受使用“=~”及“!~”匹配操作符的位置,通常包括case语句中的selector,以及节点名称匹配的位置;
它们不能传递给函数或用于资源属性的定义;
puppet中的正则表达式支持使用(?<ENABLED OPTION>:<SUBPATTERN)和(?-<DISENABLED OPTION>:<SUBPATTERN)2个特殊符号
例如下面的实例表示做正则表达式匹配时已用选项“i”(忽略字符大小写),但不支持使用"m"(把.当做换行符)和"x"(忽略模式中的空白字符和注释)
$packages = $operatingsystem ? {
/(?i-mx:ubuntu|debian)/=> 'apache2', ### ?固定格式,i启动忽略大小写,禁用吧.当做换行符,启用忽略模式中的空白字符和注释
/(?i-mx:centos|fedora|redhat)/ => 'httpd',
}

###示例:自定义变量
[root@l-mem-test2 tmp]# cat test7.pp
$pkgname='haproxy'
package {$pkgname:## 注意:title可不用引号,或使用双引号,不能使用单引号
ensure => present,
}
[root@l-mem-test2 tmp]# rpm -q haproxy
package haproxy is not installed
[root@l-mem-test2 tmp]# puppet apply test7.pp  -v
info: Applying configuration version '1483605620'
notice: /Stage[main]//Package[haproxy]/ensure: created
notice: Finished catalog run in 7.32 seconds
[root@l-mem-test2 tmp]# rpm -q haproxy
haproxy-1.5.4-3.el6.x86_64
例子factor变量:
[root@l-mem-test2 tmp]# cat test8.pp
file {'/tmp/issue.test':
ensure  => file,
content => $operatingsystem,
}
[root@l-mem-test2 tmp]# cat issue.test
CentOS


5、常见的变量操作符

常用操作符:
比较操作符
== 等于
!= 不等于
<
>
<=
>=
=~ 正则匹配
!~ 不匹配
in 是否存在某个集合中
布尔操作符
and
or
!
运算操作符
+
-
*
/
<< 左移位
>> 右移位


6、puppet的条件表达式
(1、)if语句
单分之
if 1>3 {
}
双分之
if 1>2{
}
else{
}
多分支
if 1>2{
}elsif 1>3{
}else{
}
if的条件

变量:有值为真,无值为假, 未定义变量也为假
表达式: 大于、小于、等于、不等于 可以嵌套
函数:支持函数
###示例1:
[root@l-mem-test2 tmp]# cat test10.pp
if $operatingsystem =~ /^(?i-mx:(centos|redhat|fedora))/{
notice ("Welcome to $1 system.")
}
[root@l-mem-test2 tmp]# puppet apply test10.pp
notice: Scope(Class[main]): Welcome to CentOS system.
notice: Finished catalog run in 0.02 seconds
###示例2:
[root@l-mem-test2 tmp]# cat test11.pp
if $operatingsystem == 'CentOS'{
notify {'centos':message => "welcome to CentOS system.",}
}elsif $operatingsystem == 'RedHat'{
notify {'redhat':message => "welcome to RedHat system.",}
}else{
notify {'other':message => "welcome to the system",}
}
(2)、case语句(匹配第一个满足的执行就结束)

语法:
case CONTORL_EXPRESS{
case2:{xx}
case1,case4: {xxx}
case2,case5:{xxx}
/^(Debian|Ubuntu)$/:{notice{"welcome to $1 system"}}  ## 可基于正则匹配,用引用$1
default:{xxx}
}
case语句的条件

可是一个值
可以是变量
可以使表达式
可以使函数

(3)、selectors语句
跟case语句很像,但区别是case直接返回一个动作,而selectors返回一个值
语法:
CONTORL_VARIABLE ? {
case1 => value1
case2 => value2
...
defalut => valueN
}
###示例:
[root@l-mem-test2 tmp]# cat test12.pp
$webserver = $operatingsystem ? {
/^(?i-mx:centos|fedora|redhat)/ => 'httpd',
/^(?i-mx:ubutu|debian)/ => 'apache',
}
$webprovider = $operatingsystem ? {
/^(?i-mx:centos|fedora|redhat)/ => 'yum',
/^(?i-mx:ubutu|debian)/ => 'apt',
}
package {"$webserver":
ensure => present,
provider => $webprovider,
}
上边的例子表示 $operationgsystem匹配如果是 ubuntu或者是debian那么 值是apache2,最后再将apache2赋值给$webserver


7、puppet的类class

(1)、概述:puppet类(为了通用目的或目标组织在一起的一个或多个资源;只有调用才能执行,声明才能被使用),使用 include CLASS_NAME 或者 class {'CLASS_NAME':}就可以调用了。

###示例1:
[root@l-mem-test2 tmp]# cat test13.pp
class nginx {
package {'httpd':
ensure => present,
}
service {'httpd':
ensure => true,
require => Package['httpd'],
}
}
# 常用的两种方式
#include nginx              # 第一种声明方式
class {'nginx':}            # 第二种声明方式
[root@l-mem-test2 tmp]# puppet apply test13.pp
notice: /Stage[main]/Nginx/Package[httpd]/ensure: created
notice: /Stage[main]/Nginx/Service[httpd]/ensure: ensure changed 'stopped' to 'running'
notice: Finished catalog run in 10.06 seconds


(2)、带参数的类:

格式:
class my_class (para1='val1',para2='val2'){
... puppet code ...
}


###示例:
class myql ($user = 'mysql',$port = 3306){
...
}
class {'mysql':
user = mysqlserver,     #给user赋值,不给port赋值则使用默认值3306
}


###示例:
[root@l-mem-test2 tmp]# cat test14.pp
$webserver = $operatingsystem ?{
/^(?i-mx:redhat|centos|fedora)/ => "httpd",
/^(?i-mx:ubuntu|debian)/ => "apache2",
}
class httpd ($pkgname = 'apache2'){
package {"$pkgname":
ensure => present,
}
service {"$pkgname":
ensure => true,
require => Package["$pkgname"],
}
}
class {"httpd":
pkgname => $webserver,
}
执行:
[root@l-mem-test2 tmp]# puppet apply test14.pp -v
info: Applying configuration version '1483693735'
notice: /Stage[main]/Httpd/Package[httpd]/ensure: created
notice: /Stage[main]/Httpd/Service[httpd]/ensure: ensure changed 'stopped' to 'running'
notice: Finished catalog run in 10.27 seconds
[root@l-mem-test2 tmp]# rpm -q httpd
httpd-2.2.15-55.el6.centos.2.x86_64
[root@l-mem-test2 tmp]# netstat -lntup|grep 80
tcp        0      0 :::80                       :::*                        LISTEN      23133/httpd


(3)、类的继承及清单的导入:
class C_NAME inherits PARENG_CALSS_NAME{
}
子类的命名方式:nginx::rproxy#父类::子类
基类:安装nginx
子类1:提供web配置的配置文件
子类2:提供反向代理的配置文件
###示例:

[root@l-mem-test2 tmp]# cat test15.pp
class httpd {                 ### 定义基类
package {"httpd":
ensure => present,
}
}
class httpd::rproxy inherits httpd{              ## 定义子类 httpd::rproxy inherits 父类 #固定格式
file {'/tmp/qw.conf':
ensure => file,
source => "/tmp/xxx.conf",
notify => Service['httpd'],
}
service {'httpd':
ensure => true,
}
}
class httpd::web inherits httpd{
file {'/tmp/qw.conf':
ensure => file,
source => "/tmp/xxxweb.conf",
notify => Service['httpd'],
}
service {'httpd':
ensure => true,
}
}
清单的导入:
[root@l-mem-test2 tmp]# cat node.pp
import "/tmp/test15.pp"                   ## 导入清单
include httpd::rproxy                     ## 声明
------ 执行
[root@l-mem-test2 tmp]# puppet apply node.pp -v
info: Applying configuration version '1483695028'
info: FileBucket adding {md5}2cb3f4eea6c0334eb8bca787e704622b
info: /Stage[main]/Httpd::Rproxy/File[/tmp/qw.conf]: Filebucketed /tmp/qw.conf to puppet with sum 2cb3f4eea6c0334eb8bca787e704622b
notice: /Stage[main]/Httpd::Rproxy/File[/tmp/qw.conf]/content: content changed '{md5}2cb3f4eea6c0334eb8bca787e704622b' to '{md5}6de9439834c9147569741d3c9c9fc010'
info: /Stage[main]/Httpd::Rproxy/File[/tmp/qw.conf]: Scheduling refresh of Service[httpd]
notice: /Stage[main]/Httpd::Rproxy/Service[httpd]: Triggered 'refresh' from 1 events
notice: Finished catalog run in 0.61 seconds
[root@l-mem-test2 tmp]# cat qw.conf
xxx


8、模块
为了实现某种完备功能而组织成一个独立的,自我包含的目录结构:模块
总结:模块是目录结构,目录名称即为模块名
注意:模块名称以小写字母开头,但不能使用main或settings作为模块名。
目录结构:
/tmp/modules/
nginx/
files/           :文件存储目录
nginx.conf
manifests/:清单存储目录
init.pp         #必须有的 必须包含且只能包含与模块同名的类
nginx.pp     # 每个清单通常只包含一个类,其他清单不能包含模块名的类
...
templates/       :模板存放目录
*.erb
lib/:ruby插件存储目录用于实现自定义功能,一般很少用到
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  运维 自动化 puppet