设为首页 收藏本站
查看: 1745|回复: 0

[经验分享] Puppet自动化管理(1)

[复制链接]

尚未签到

发表于 2018-8-1 12:38:16 | 显示全部楼层 |阅读模式
  puppet介绍
  puppet是一个IT基础设施自动化管理工具,它能够帮助管理员管理基础设施的整个生命周期:供应 配置 联动(编排) 报告
  支持的并发性很好,适用于企业级较大规模
  puppet是用ruby语言写的  facter是puppet的一个模块
  ansible靠模块,puppet靠资源;puppet的模块类似于ansible的角色。
  定义模块的文件叫清单(manifest),主要是定义资源的叫资源清单。如果定义的清单是为了设定目标主机到底调用哪些模块的,叫做站点清单(site manifest)。
  基本工作逻辑:
  puppet是master-agent模型,master为了实现代码复用定义了很多模块。而后可以为每一个被管控主机定义一个站点清单的配置,说明这个主机要调用那些模块。接着,每一个agent主机每隔固定时长(通常默认为30分钟)到master端请求自己的相关配置。master端通过证书去识别客户端身份,获取其主机名称标识,从而在本地查找这个主机相关的配置,拿出来模块并发送给目标主机,从而实现管控。
  它的好处在于,一旦我们定义好了puppet的master上的每一主机相关配置,那每一个主机放在那里你就不用管它了。他如果出了故障,最长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可以看到很多子命令
DSC0000.jpg

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

  子命令也有子命令
  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运行,除此之外还有如下选项:
DSC0002.jpg

  -h 帮助
  -v 显示详细信息
  -d 打开调试信息(会输出许多信息)
  -e 直接执行命令
  -l 指定日志文件,否则内容可能会直接输出到标准输出
  -noop 使用'noop'模式,会测试的跑一遍而不真正执行
  资源类型:
  1group
  创建组
  Manage groups.
  属性:
  name:组名;
  gid:GID;
  system:是否为系统组,true OR false;
  ensure:目标状态,present/absent;
  members:成员用户;
  编辑文件:
DSC0003.jpg

  如果name跟title一样的话可以省略,如果不一样就不能省略
  执行:
DSC0004.jpg

  创建成功:
DSC0005.jpg

  2、user
  创建用户
  Manage users.
  属性:
  name:用户名;
  uid: UID;
  gid:基本组ID;
  groups:附加组,不能包含基本组;
  comment:注释信息;
  expiry:过期时间;
  home:家目录路径;
  shell:默认shell类型;
  system:是否为系统用户;
  ensure:present/absent;
  password:加密后的密码串;
  (属性可以什么都不写,只要写上ensure=>present即可创建用户)
  编辑文件:
DSC0006.jpg

  执行:
DSC0007.jpg

  创建成功:
DSC0008.jpg

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

  我们再来定义一个user,
  当我们要指定多个附加组的时候格式如下:
DSC00010.jpg

  依赖关系:
  ·资源引用:
  Type['title']
  类型的首字母必须大写!
  ·关系元参数:before/require两种方法都可以
  A before B: B依赖于A,定义在A资源中;
  {
  ...
  before => Type['B'],
  ...
  }
  B require A: B依赖于A,定义在B资源中;
  {
  ...
  require => Type['A'],
  ...
  }
  如果定义一个用户指明的附加组是不存在的话,
  当我们使用noop模式的时候不会报错:
DSC00011.jpg

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

  因为noop只能检查语法错误,而这里是依赖的资源不存在,是资源环境的问题。
  这里就提到了依赖关系,也就是说,我们必须先创建一个组,才能创建一个以那个组为附加组的用户。那我们现在就来创建一下,为了方便演示,我们就只创建一个组。
  有两种方式,一种是在被依赖资源上用before:
DSC00013.jpg

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

  这两种方法都可以,意思就是,先建立一个redhat组,然后再创建用户linux。
  这回再运行,就没问题了:
DSC00015.jpg

  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,)
  编辑文件:
DSC00016.jpg

  运行,安装完成:
DSC00017.jpg

  注意,如果是指定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:是否支持restart。true表示支持,false表示不支持。
  hasstatus:是否支持状态探测。
  start:手动定义启动命令;
  stop:手动定义停止命令;
  status:手动定义探测服务状态命令。
  restart:通常用于定义reload操作;
  编辑文件:
DSC00018.jpg

  运行,启动成功:
DSC00019.jpg

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

  如图所见,果然是不行的
   DSC00021.jpg
  因此,service要依赖于对应程序的程序包,用我们刚才刚学过的依赖,定义一下:
DSC00022.jpg

  安装成功:
DSC00023.jpg

  并且也启动成功:
DSC00024.jpg

  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:时间戳;
  编辑文件:
DSC00025.jpg

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

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

  运行成功:
DSC00028.jpg

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

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

  运行成功:
DSC00031.jpg

  创建成功:
DSC00032.jpg

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

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

  创建成功
DSC00035.jpg

  可见,如果我们指定一个目录,但是又没有指定生成的方式,就会创建目录
  我们再试着向目录里拷贝文件:
DSC00036.jpg

  指定源,还要记得指定递归:
DSC00037.jpg

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

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

  它的复制机制是,先创建目录,然后将文件一个一个复制过去。
  那我们把刚才创建的目录以及目录下的文件都删掉,再来创建一个.pp文件:
DSC00040.jpg

  这次我们定义两个文件
DSC00041.jpg

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

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

  可见,puppet并不支持把文件复制成目录(本来也没办法复啊)。也就是说,即使你指定了ensure为directory类型,但是你的source却指定的是文件,那么它就会创建文件并复制内容。如果你的source指定了不止一个文件的话,那么它只会复制第一个文件的内容。
  接下来,我们创建一个链接类型:
  链接指向之前创建过的text.txt文件
DSC00044.jpg

  运行成功:
DSC00045.jpg

  创建链接成功:
DSC00046.jpg

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

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

  我们不能只定义资源,还得定义它们之间的依赖关系,service依赖于file,file依赖于package。
  一共有几种不同的方式定义:
  方法一:
DSC00049.jpg

  方法二:
DSC00050.jpg

  方法三:
DSC00051.jpg

  但是呢,我们如果修改了配置文件之后需要重启,目前这个脚本不会重启,因为它发现服务启动了之后就不会执行启动操作了,因此我们要加入下一个关系,叫通知关系。
  通知关系:通知相关的其它资源进行“刷新”操作;
  notify
  A notify B:B依赖于A,且A发生改变后会通知B;
  {
  ...
  notify => Type['B'],
  ...
  }
  subscribe
  B subscribe A:B依赖于A,且B监控A资源的变化产生的事件;
  {
  ...
  subscribe => Type['A'],
  ...
  }
  因此我们应该定义,如果配置文件修改了,就通知service重启服务:
  方法一:
DSC00052.jpg

  方法二,可以用波浪线:
DSC00053.jpg

  方法三:
DSC00054.jpg

  这样就可以在修改完配置文件之后重启服务了。
  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:仅接收到订阅的资源的通知时方才运行;
  编辑文件:
  先不指定幂等关系,只是单纯的创建个文件:
DSC00055.jpg

  第一次运行,成功:
DSC00056.jpg

  创建成功
DSC00057.jpg

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

  就报错了,因为文件已经存在了。
  因此我们应该稍微修改一下文件,给它加一个限定条件,如果文件不存在就创建:
DSC00059.jpg

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

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

  仅此路径表示的文件不存在时,command方才执行。
  我们还可以使用onlyif或者unless:
  可以看到,当一个用户存在的时候,是可以执行id+用户名这个命令的,如果用户不存在就不能执行:
DSC00062.jpg

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

  这样就是如果用户不存在就创建,存在就不执行。
  7、cron
  计划任务
  command:要执行的任务;
  ensure:present/absent;
  定义时间:
  hour:
  minute:
  monthday:
  month:
  weekday:
  user:以哪个用户的身份运行命令
  target:添加为哪个用户的任务
  name:cron job的名称;
  编辑文件:
DSC00064.jpg

  运行成功:
DSC00065.jpg

  计划任务添加成功:
DSC00066.jpg

  8、notify
  向屏幕显示一段话
  属性:
  message:信息内容
  name:信息名称;
  编辑文件:
DSC00067.jpg

  运行,显示成功:
DSC00068.jpg

  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部分:
DSC00069.jpg

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

  这种标签定义的意义可以用于修改了配置文件之后使用,就会触发更新配置文件和重新启动了。
  变量
  ·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查看里面有这么几个变量
DSC00071.jpg

  我们可以使用它:
DSC00072.jpg

  运行一下,显示成功:
DSC00073.jpg

  2.内建变量:
  master端变量
  $servername   服务器名称
  $serverip  服务器IP
  $serverversion  服务器版本
  agent端变量
  $clientcert  证书
  $clientversion  客户端版本
  $environment  客户端所处环境
  parser变量
  $module_name
  3.用户自定义变量:
DSC00074.jpg

  ·变量作用域,称为Scope;
  Scope是一个特定的代码区域,用于同程序中的其他代码隔离开来。
  在puppet中,scope可用于限定变量及资源默认属性的作用范围,但不能用于限定资源名称及资源引用的生效范围。
DSC00075.jpg

  顶级作用域top scope:   ($::var_name调用全局变量)
  节点作用域node scope
  类作用域class scope
  在顶级作用域上定义的变量对所有节点和类都有效,在节点上定义的作用域只在当前节点上有效。查找的时候从内到外从小到大查找,最内层的优先级最高。
  如果想跨类调用,可以使用变量的完全限定名称。
DSC00076.jpg

  操作符
  比较操作符    布尔操作符   算术操作符
  << 左移位(相当于成以10);>>右移位(相当于除以10)
DSC00077.jpg

  << 左移位(相当于成以10);>>右移位(相当于除以10)
  流程控制
  puppet流程控制语句:
  1、if语句:
DSC00078.jpg

  CONDITION的给定方式:
  (1) 变量
  (2) 比较表达式
  (3) 有返回值的函数
  例子1:
DSC00079.jpg

  如果版本号是7就安装mariadb包,否则就安装mysql包
  例子2:
DSC00080.jpg

DSC00081.jpg

  2、case语句:
DSC00082.jpg

  CONTROL_EXPRESSION:
  (1) 变量
  (2) 表达式
  (3) 有返回值的函数
  各case的给定方式:
  (1) 直接字串;
  (2) 变量
  (3) 有返回值的函数
  (4) 正则表达式模式;
  (5) default
  将刚才的if的例子2改成case方式,如下:
DSC00083.jpg

  3、selector语句
  selector与case类似,只不过就是,case是满足条件执行代码,而selector是满足条件返回一个值。
DSC00084.jpg

  CONTROL_VARIABLE的给定方法:
  (1) 变量
  (2) 有返回值的函数
  各case的给定方式:
  (1) 直接字串;
  (2) 变量
  (3) 有返回值的函数
  (4) 正则表达式模式;
  (5) default
  注意:不能使用列表格式;但可以是其它的selecor;
  因此,其实刚才的例子当中,用selector要更方便:
DSC00085.jpg

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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-544792-1-1.html 上篇帖子: puppet常用资源类型与使用方法 下篇帖子: puppet的使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表