Puppet自动化管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Puppet自动化管理相关的知识,希望对你有一定的参考价值。

puppet介绍

puppet是一个IT基础设施自动化管理工具,它能够帮助管理员管理基础设施的整个生命周期:供应 配置 联动(编排) 报告

支持的并发性很好,适用于企业级较大规模

puppet是用ruby语言写的  facter是puppet的一个模块

ansible靠模块,puppet靠资源;puppet的模块类似于ansible的角色。

定义模块的文件叫清单(manifest),主要是定义资源的叫资源清单。如果定义的清单是为了设定目标主机到底调用哪些模块的,叫做站点清单(site manifest)

 

基本工作逻辑:

puppetmaster-agent模型,master为了实现代码复用定义了很多模块。而后可以为每一个被管控主机定义一个站点清单的配置,说明这个主机要调用那些模块。接着,每一个agent主机每隔固定时长(通常默认为30分钟)master端请求自己的相关配置。master端通过证书去识别客户端身份,获取其主机名称标识,从而在本地查找这个主机相关的配置,拿出来模块并发送给目标主机,从而实现管控。

它的好处在于,一旦我们定义好了puppetmaster上的每一主机相关配置,那每一个主机放在那里你就不用管它了。他如果出了故障,最长30分钟以后能自己修复回来,只要是我们管控的目标范围内的。

 

官方网站:

https://puppet.com/products/open-source-projects

下载路径:

https://yum.puppet.com/

 

 

三层模型

Configuration Language配置语言

Transactionl Layer事物关系层

Resource Abstraction Layer资源抽象层

两种使用模型

单机使用:手动应用清单

puppet apply

master/agent:由agent周期性地向Master请求清单并自动应用于本地;

master:puppet,puppet-server

agent:puppet

 

安装:yum install puppet

agent端只需要安装puppet,master才需要安装puppet-server

 

主程序:/usr/bin/puppet

 

使用puppet help可以看到很多子命令

技术分享图片

如果想看某一个子命令的帮助,也可以使用help查看:

技术分享图片

子命令也有子命令



puppet资源

·资源抽象的纬度(RAL如何抽象资源的?):

类型:具有类似属性的组件,例如package、service、file;

将资源的属性或状态与其实现方式分离;

仅描述资源的目标状态,也即期望其实现的结果状态,而不是具体过程;

 

RAL由“类型”和提供者(provider);

 

·puppet describe:

Prints help about Puppet resource types, providers, and metaparameters.

基础使用语法:

puppet describe [-h|--help] [-s|--short] [-p|--providers] [-l|--list] [-m|--meta] [type]

-l:列出所有资源类型;

-s:显示指定类型的简要帮助信息;

-m:显示指定类型的元参数,一般与-s一同使用;

puppet describe group 参数描述

puppet describe -s group 简要描述

puppet describe -s group -m 多显示了元参数(描述属性)

常用元参数:before,require,notify,subscribe

-p:某种资源的具体实现方法

 

·资源定义:向资源类型的属性赋值来实现,可称为资源类型实例化;

定义了资源实例的文件即清单,manifest;

 

1、定义资源的语法:

Vim XXX.pp  #建立一个后缀为pp的文件

type {'title':

attribute1 => value1,

atrribute2 => value2,

……

}

注意:type为资源类型,必须使用小写字符;title为自己起的名字,是一个字符串,在同一类型中必须惟一;每一个键值对用逗号隔开,最后一个键值对后面的逗号可有可无。

puppet中定义的每一个资源都必须具有幂等性,意思就是执行一次操作与执行n次操作结果必须是一样的。例如有一个操作是创建文件,那么第一次操作会创建文件,第二次再执行时文件已经存在就不会创建文件了这样就不幂等,因此如果我们想让它幂等,就给它加一个条件:“如果文件不存在”就创建目录,这样无论执行多少次都是幂等的了。

 

2、资源属性中的三个特殊属性:

Namevar, 可简称为name;

ensure:资源的目标状态;

Provider:指明资源的管理接口;

 

3、资源清单文件使用:

使用puppet apply file运行,除此之外还有如下选项:

                技术分享图片

-h 帮助

-v 显示详细信息

-d 打开调试信息(会输出许多信息)

-e 直接执行命令

-l 指定日志文件,否则内容可能会直接输出到标准输出

-noop 使用'noop'模式,会测试的跑一遍而不真正执行

 

 

 

资源类型:

1group

创建组

Manage groups.

属性:

name:组名;

gid:GID;

system:是否为系统组,true OR false;

ensure:目标状态,present/absent;

members:成员用户;

 

编辑文件:

技术分享图片

如果nametitle一样的话可以省略,如果不一样就不能省略

执行:

技术分享图片

创建成功:

技术分享图片


2、user

创建用户

Manage users.

属性:

name:用户名;

uid: UID;

gid:基本组ID;

groups:附加组,不能包含基本组;

comment:注释信息;

expiry:过期时间;

home:家目录路径;

shell:默认shell类型;

system:是否为系统用户;

ensure:present/absent;

password:加密后的密码串;

(属性可以什么都不写,只要写上ensure=>present即可创建用户)

 

编辑文件:

技术分享图片

执行:

技术分享图片

创建成功:

技术分享图片

再看一下mygrp组,user1已经作为附加组加入mygrp中了:

技术分享图片


我们再来定义一个user,

当我们要指定多个附加组的时候格式如下:

技术分享图片


依赖关系:

·资源引用:

Type['title']

类型的首字母必须大写!

 

·关系元参数:before/require两种方法都可以

A before B: B依赖于A,定义在A资源中;

{

...

before => Type['B'],

...

}

B require A: B依赖于A,定义在B资源中;

{

...

require => Type['A'],

...

}

 

 

如果定义一个用户指明的附加组是不存在的话,

当我们使用noop模式的时候不会报错:

技术分享图片

但是当我们真正去执行的时候,就报错了:

技术分享图片

因为noop只能检查语法错误,而这里是依赖的资源不存在,是资源环境的问题。

这里就提到了依赖关系,也就是说,我们必须先创建一个组,才能创建一个以那个组为附加组的用户。那我们现在就来创建一下,为了方便演示,我们就只创建一个组。

有两种方式,一种是在被依赖资源上用before:

技术分享图片

另一种是在依赖的资源上用require:

技术分享图片

这两种方法都可以,意思就是,先建立一个redhat组,然后再创建用户linux。

这回再运行,就没问题了:

技术分享图片


3、package:

安装包

Manage packages.

属性:

ensure

安装:installed,present, 'any version string(implies present)'

最新版本:latest

卸载:absent,purged

name:包名;

source:程序包来源,仅对不会自动下载相关程序包的provider有用,例如rpm或dpkg;如果是URL会自动下载到本地。

provider:指明安装方式;

platform:平台(i386,x86_64,)

 

编辑文件:

技术分享图片

运行,安装完成:

技术分享图片

注意,如果是指定rpm包直接在本地安装也是可以的,如果使用这种方式就是用本地的source直接安装的话,很有可能无法解决依赖关系。所以当我们使用source直接指定rpm包安装时,建议不要使用rpm作为provider,而是指明用yum安装,因为这样能帮我们解决依赖关系。

 

 

4、service:

关于服务的操作

Manage running services.

属性:

ensure:服务是否开启。有效值为`stopped` (或 `false`), `running` (或 called `true`).

name:控制服务名字

enable:是否设定服务为开机自启状态。 有效值为 `true`, `false`, `manual`.

path:查找init脚本的搜索路径。多值应该由逗号分隔或设置为数组。默认为/etc/init.d/;

binary:启动服务的二进制文件程序路径

hasrestart:是否支持restarttrue表示支持,false表示不支持。

hasstatus:是否支持状态探测。

start:手动定义启动命令;

stop:手动定义停止命令;

status:手动定义探测服务状态命令。

restart:通常用于定义reload操作;

 

编辑文件:

技术分享图片

运行,启动成功:

技术分享图片


如果你定义一个service,但是那个程序包没有安装,是否能启动呢?那我们来试一下:

技术分享图片

如图所见,果然是不行的

技术分享图片

因此,service要依赖于对应程序的程序包,用我们刚才刚学过的依赖,定义一下:

技术分享图片

安装成功:

技术分享图片

并且也启动成功:

技术分享图片


5、file:

文件

Manages files, including their content, ownership, and permissions.

ensure: `present`, `absent`,(建议直接给后面三个值:) `file`, `directory`, and `link`.

file:类型为普通文件,其内容由content属性生成或复制由source属性指向的文件路径来创建;

link:类型为符号链接文件,必须由target属性指明其链接的目标文件;

directory:类型为目录,可通过source指向的路径复制生成,recurse属性指明是否递归复制;

path:文件路径;(因为文件没有name属性,所以在定义的时候title部分写的就是path

source:源文件;(如果是复制的话就用这个,如果是复制多个文件,那么path就要定义一个目录了)

content:文件内容;(如果是自定义的话就用这个)

recurse:递归

target:符号链接的目标文件;

owner:属主

group:属组

mode:权限;

atime/ctime/mtime时间戳;            

 

编辑文件:

技术分享图片

那我们在文件里写了源地址,我们就要去创建它并且在里面放一个redis.conf文件供我们复制。

技术分享图片

为了便于区分,我们稍微改一下这个redis.conf文件,监听本机所有地址。

技术分享图片

运行成功:

技术分享图片

查看一下文件,确实复制过去了:

技术分享图片


刚才是复制一个文件,我们也可以自己制定内容去生成一个文件:

技术分享图片

运行成功:

技术分享图片

创建成功:

技术分享图片


刚才两个都是生成文件,我们还可以生成一个目录:

技术分享图片

只需要这么写,就可以生成一个目录

技术分享图片

创建成功

技术分享图片

可见,如果我们指定一个目录,但是又没有指定生成的方式,就会创建目录


我们再试着向目录里拷贝文件:

技术分享图片

指定源,还要记得指定递归:

技术分享图片

可以看到,它将文件一个一个复制过去了:

技术分享图片

复制成功,文件夹下的3个文件都过去了:

技术分享图片

它的复制机制是,先创建目录,然后将文件一个一个复制过去。

 

那我们把刚才创建的目录以及目录下的文件都删掉,再来创建一个.pp文件:

技术分享图片

这次我们定义两个文件

技术分享图片

我们运行之后发现它并没有生成目录,而是生成了名为test.dir的文件

技术分享图片

再查看一下文件内容,发现它复制的是第一个文件的内容:

技术分享图片

可见,puppet并不支持把文件复制成目录(本来也没办法复啊)。也就是说,即使你指定了ensuredirectory类型,但是你的source却指定的是文件,那么它就会创建文件并复制内容。如果你的source指定了不止一个文件的话,那么它只会复制第一个文件的内容。

 

接下来,我们创建一个链接类型:

链接指向之前创建过的text.txt文件

技术分享图片

运行成功:

技术分享图片

创建链接成功:

技术分享图片


练习:

学过了之前这几个资源,目前为止,我们可以完成一整套的操作了,那我们现在来定义一下试试:

技术分享图片

看一下原本默认的/etc/redis.conf文件属性是这样的:

技术分享图片

我们不能只定义资源,还得定义它们之间的依赖关系,service依赖于filefile依赖于package

一共有几种不同的方式定义:

方法一:

技术分享图片

方法二:

技术分享图片

方法三:

技术分享图片


但是呢,我们如果修改了配置文件之后需要重启,目前这个脚本不会重启,因为它发现服务启动了之后就不会执行启动操作了,因此我们要加入下一个关系,叫通知关系。

通知关系:通知相关的其它资源进行“刷新”操作;

notify

A notify B:B依赖于A,且A发生改变后会通知B;

{

...

notify => Type['B'],

...

}

subscribe

B subscribe A:B依赖于A,且B监控A资源的变化产生的事件;

{

...

subscribe => Type['A'],

...

}                   

 

因此我们应该定义,如果配置文件修改了,就通知service重启服务:

方法一:

技术分享图片

方法二,可以用波浪线:

技术分享图片

方法三:

技术分享图片

这样就可以在修改完配置文件之后重启服务了。


6、exec:

自定义命令。注意,命令必须是幂等的。

**command** (*namevar*):要运行的命令;

cwd:The directory from which to run the command.

**creates**:文件路径,仅此路径表示的文件不存在时,command方才执行;

user/group:运行命令的用户身份;

path:用于命令执行的搜索路径。如果没有指定路径,命令必须完全限定。有两种方式定义path

path => '/bin:/sbin:/usr/bin:/usr/sbin' 用冒号隔开

path => ['/bin','/sbin','/usr/bin','/usr/sbin'] 用中括号并用逗号隔开

onlyif:此属性指定一个命令,此命令正常(退出码为0)运行时,当前command才会运行;

unless:此属性指定一个命令,此命令非正常(退出码为非0)运行时,当前command才会运行;

refresh:重新执行当前command的替代命令;

refreshonly:仅接收到订阅的资源的通知时方才运行;

 

编辑文件:

先不指定幂等关系,只是单纯的创建个文件:

技术分享图片

第一次运行,成功:

技术分享图片

创建成功

技术分享图片

那我们现在再来运行一遍:

技术分享图片

就报错了,因为文件已经存在了。

因此我们应该稍微修改一下文件,给它加一个限定条件,如果文件不存在就创建:

技术分享图片

这样无论运行多少遍都没问题了:

技术分享图片

除了用那种命令的条件,还可以用creates属性:

技术分享图片

仅此路径表示的文件不存在时,command方才执行。

 

我们还可以使用onlyif或者unless

可以看到,当一个用户存在的时候,是可以执行id+用户名这个命令的,如果用户不存在就不能执行:

技术分享图片

因此,我们可以使用这一点,编写一个文件:

技术分享图片

这样就是如果用户不存在就创建,存在就不执行。

 

7、cron

计划任务

command:要执行的任务;

ensure:present/absent;

定义时间:

hour

minute:

monthday:

month:

weekday

user:以哪个用户的身份运行命令

target:添加为哪个用户的任务

name:cron job的名称;

 

编辑文件:

技术分享图片

运行成功:

技术分享图片

计划任务添加成功:

技术分享图片


8、notify

向屏幕显示一段话

属性:

message:信息内容

name:信息名称;

 

编辑文件:

技术分享图片

运行,显示成功:

技术分享图片


9、非核心类型常用资源:

yumrepo

host

 

 

tag

可以为资源定义tag,格式:

            type{'title':

                ...

                tag => 'TAG1',

            }

           

            type{'title':

                ...

                tag => ['TAG1','TAG2',...],

            }     

           

手动调用tag

    puppet apply --tags TAG1,TAG2,... FILE.PP

 

编辑文件:

我们定义一个tag,让调用tag的时候就会只执行file的部分,然后我们在file部分里面又定义了notify触发service部分:

技术分享图片

使用--tags调用我们定义的tag(这样的话就不会再运行package):

技术分享图片

这种标签定义的意义可以用于修改了配置文件之后使用,就会触发更新配置文件和重新启动了。




变量

·variable定义规则:

$variable_name=value  (定义变量的时候也要加$符号)

 

数据类型:

字符型:引号可有可无;但单引号为强引用,双引号为弱引用;

数值型:默认均识别为字符串,仅在数值上下文才以数值对待;

数组:[]中以逗号分隔元素列表;

布尔型值:true, false;

hash:{}中以逗号分隔k/v数据列表;键为字符型,值为任意puppet支持的类型;{ 'mon' => 'Monday', 'tue' => 'Tuesday', }

undef:未定义 ;

正则表达式:

(?<ENABLED OPTION>:<PATTERN>)

(?-<DISABLED OPTION>:<PATTERN>)

OPTIONS

i:忽略字符大小写;

m:把.当换行符;

x:忽略<PATTERN>中的空白字符

我们一般用这种格式:(?i-mx:PATTERN)意思是忽略字符大小写,不把.当换行符,不忽略空白字符

注意:正则表达式不能赋值给变量 ,仅能用在接受=~或!~操作符的位置;

 

 

·puppet的变量种类:

1.facts 系统级的环境变量:

由facter提供;top scope;可以使用facter -p查看

(如果是apply的话,它在运行的时候会先收集本机上的所有facts变量。

     如果是master/agent的话,agent会在请求之前先向master发送自己的主机名和facts,然后在请求自己相关的配置。)

 

使用facter -p查看里面有这么几个变量

                技术分享图片

我们可以使用它:

                技术分享图片

运行一下,显示成功:

                技术分享图片  


2.内建变量:

master端变量

                 $servername   服务器名称

$serverip  服务器IP

$serverversion  服务器版本

agent端变量

            $clientcert  证书

$clientversion  客户端版本

$environment  客户端所处环境

parser变量

            $module_name 

3.用户自定义变量:

            技术分享图片


·变量作用域,称为Scope;

Scope是一个特定的代码区域,用于同程序中的其他代码隔离开来。

puppet中,scope可用于限定变量及资源默认属性的作用范围,但不能用于限定资源名称及资源引用的生效范围。

        技术分享图片

顶级作用域top scope:   ($::var_name调用全局变量)

节点作用域node scope

类作用域class scope

在顶级作用域上定义的变量对所有节点和类都有效,在节点上定义的作用域只在当前节点上有效。查找的时候从内到外从小到大查找,最内层的优先级最高。

如果想跨类调用,可以使用变量的完全限定名称。

        技术分享图片

操作符

比较操作符    布尔操作符   算术操作符

<< 左移位(相当于成以10);>>右移位(相当于除以10

技术分享图片

<< 左移位(相当于成以10);>>右移位(相当于除以10



流程控制

puppet流程控制语句:

1、if语句:

        技术分享图片

CONDITION的给定方式:

(1) 变量

(2) 比较表达式

(3) 有返回值的函数

 

例子1

        技术分享图片

如果版本号是7就安装mariadb包,否则就安装mysql

   例子2

            技术分享图片

            技术分享图片


2、case语句:

        技术分享图片

CONTROL_EXPRESSION:

(1) 变量

(2) 表达式

(3) 有返回值的函数

  各case的给定方式:

(1) 直接字串;

(2) 变量

(3) 有返回值的函数

(4) 正则表达式模式;

(5) default

 

将刚才的if的例子2改成case方式,如下:

        技术分享图片


3、selector语句

selectorcase类似,只不过就是,case是满足条件执行代码,而selector是满足条件返回一个值。

        技术分享图片

CONTROL_VARIABLE的给定方法:

(1) 变量

(2) 有返回值的函数

各case的给定方式:

(1) 直接字串;

(2) 变量

(3) 有返回值的函数

(4) 正则表达式模式;

(5) default

注意:不能使用列表格式;但可以是其它的selecor;

 

因此,其实刚才的例子当中,用selector要更方便:

技术分享图片

用这种方式,也能实现同样的功能。


以上是关于Puppet自动化管理的主要内容,如果未能解决你的问题,请参考以下文章

自动化运维工具Puppet

使用puppet实现自动化运维

自动化运维工具Puppet(管理资源)

自动化运维工具puppet详解

自动化运维---puppet入门

puppet 学习总结——puppet 入门详解