运维自动化管理工具之Puppet

一、相关概念

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

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插件存储目录用于实现自定义功能,一般很少用到


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章