运维自动化


   运维自动化是指将IT运维中日常的、大量的重复性工作自动化,把过去的手工执行转换为自动化操作,自动化是运维工作的生化,运维自动化不单纯是一个维护过程,更是一个管理的提升过程,是IT运维的最高层次,也是未来的发展趋势


   虽然无法做到完全自动化运维,但是我们应该努力尽量的大部分的实现自动化运维;  


自动化运维的层次结构


   1、第一层-------引导层 Bootstrap

   2、第二层-------配置层 Configuration

   3、第三层-------命令集控制层 Command and Control


   如图所示:各层及其实现程序


puppet 基础应用详解


Puppet简介


    由上图可知,Puppet使用在自动化运维的第二层,也就是Configuration配置层。

    Puppet是一个IT基础设施自动化管理工具,它能够帮助管理员管理基础设施的整个生命周期:供应(provisioning)、配置(configration)、联动(orchestration)及报告(reporting)

通过使用puppet,可以实现自动化重复任务、快速部署关键性应用以及在本地或者云端完成主动管理变更和快速扩展架构规模等。

    Puppet基于ruby语言开发,它对于管理员来讲是抽象的,只依赖于ruby与facter。其本身能够管理多达40多种资源,例如:file、user、group、package、service、host、cron、exec、yum repo等,适合整个生命周期;

    总结:Puppet 就是集中式的配置管理工具,通过自有配置语言对节点进行目标状态的定义,并能够基于网络实现目标状态的维护。


Mater/agent架构及工作流程


     Puppet是基于master/agent的架构

             master:中心配置库

             agent : 读取并应用配置的节点


     工作流程


puppet 基础应用详解


如上图:
agent节点发送自己的事实或者其状态的数据给master服务器;
master服务器根据agent的目标状态编译成Catalog伪代码,除此以外还将如何在节点上进行配置的相关数据和Catalog一并发送给angent端;
agent端,根据master发送的Catalog和配置数据,先于当前状态进行比较,然后进行状态的改变(或者单单进行模拟配置),并将改变结果数据发送给Master;
master端并将报告完全无障碍的通过开放API,发送给第三方工具;



Puppet术语


1、 manifest(清单)


      puppet的程序文件称作“manifest(清单)”,以.pp作为文件名后缀;

      如前所述,puppet语言的核心是“资源定义”,而定义一个资源的核心就在于描述其目标状态,而nanifest文件就是用来定义resource资源的


      “puppet apply”子命令能够将一个manifest中描述的目标状态强制实现,因此它通常以manifest文件作为参数


2、catalog(伪代码)


      puppet通过manifest同步资源时,不会直接应用manifest文件,而是要经过预先的编译过程,这是因为manifest文件中可能会包含条件判断、变量、函数以及其他的程序逻辑,实际执行中,有可能会基于层次及包含关系存在多个manifest文件,这些文件会被编译仅同一个称作“catalog”的文件,编译完成后的catalog文件仅包含各个资源以及它们同步时的次序;


3、resource (资源)


      如果把OS的所有配置,如用户账户、特定的文件、文件所属的目录、运行的服务、程序包以及cron任务等,看作是许多独立原子单元的集合的化,这些所谓的“单元”就是“资源”;不过这些资源在其大小、复杂程度以及生命周期的跨度上等多个维度上可能会各不相同

      通常来说,类属于同一种资源的属性是相近的,如文件都有其属主和属组,而用户帐号则由用户名、UID、GID等组成;不过即便是同一种资源,其在不同OS 上的实现方式却又可能各不相同,例如在windows上和linux上启动和停止服务的方式相去甚远,,因此puppet必须对资源进行某种程度的抽象;

     资源抽象:puppet在以下三个维度来对资源完成抽象

     1)相似的资源被抽象成同一种资源“类型”,如程序包资源、用户资源及服务资源等;

     2)将资源属性或状态的描述与其实现方式玻璃开来,如仅说明安装一个程序包而不用关心其具体是通过yum、pkgadd、prots或是其他方式实现;

     3)仅描述资源的目标状态,也即期望其实现的结果,而不是其具体过程,如“确定nginx运行起来”而不是具体描述为“运行nginx命令将其启动起来”;

    这三个也被称作puppet的资源抽象层(RAL),RAL由type(类型)和provider(提供者,即不同OS上特定实现)组成


4、resource declaration (资源申报)


      在为puppet定义一个资源时,需要为其指定所述的类型和资源标题,并同时配置一系列的属性和对应的值。puppet通过特有的语言来描述和管理资源

      这种语法被成为“资源申报(resource declaration)”,它是puppet语言的核心组成部分,在定义中,仅描述了资源的目标状态而没有提到为达到目标所需要采取的任何步骤

     type { 'title':

         attribute => value,

      }

     puppet有许多内置的资源类型,而通过安装插件还可以继续新增额外的类型

     可以通过官网参考页面http://docs.puppetlabs.com/references/latest.html获取详情,也可以使用“puppet describe”命令来获取puppet当前所能支持的类型列表及每种类型的详细信息;






puppet安装


     puppet的安装有三种方式

        1、gem安装(类似于perl中的cpan)

        2、源包下载 http://yum.puppetlabs.com/el/

https://yum.puppetlabs.com/el/6.5/products/x86_64/

         3、yum安装,需要配置好epel源


puppet资源介绍



# yum  -y install puppet 使用yum的方式安装puppet,版本为2.7

      puppet describe -l  列出所有资源


      其中我们重点学习notify、package、user、group、file、exec、cron、service


1、package

         puppet支持使用的软件包管理器:yum,rpm,apt,ports,gem,msi,dpkg,pkg。。。

         package的常用参数

            ensure:程序包的目标状态;

            name  :资源的名称,即软件包的名称

            provider:软件包管理器

            source  :指定程序包文件路径

           install_option :安装选项,最常用的是通过IINSTALLDIR来指定安装目录          


# rpm -q nginx
package nginx is not installed
# vim nginx.pp
  package {'nginx':
       ensure => present,
 }
# puppet apply nginx.pp
# rpm -q nginx
nginx-1.0.15-5.el6.x86_64



2、service

     常用参数

         ensure:服务的目标状态,true(running)和false(stoppd)

         enbale:是否开机自动启动,true和false

         name  :服务名称

         path  :服务脚本路径

         start :启动命令

         stop  :关闭命令

         restart:重启命令

         status :状态命令


# vim  test.pp
service {'httpd':
        ensure => true,
        enable => true,
        name   => 'httpd',
}
# puppet apply test.pp
notice: /Stage[main]//Service[httpd]/ensure: ensure changed 'stopped' to 'running'
notice: Finished catalog run in 0.74 seconds
# service httpd status
httpd (pid  18326) 正在运行...
# chkconfig --list httpd
0:off   1:off   2:on    3:on    4:on    5:on    6:off


3、user :管理用户


        常用属性

           ensure:目标状态 present或absent

           name  :用户名

           uid   : 用户ID

           system: 系统用户

           home  : 指定家目录

           shell : 默认shell

           gid   : 基本组ID

           password:用户密码

           managehome:是否创建家目录,默认为false



# vim  test.pp
user {'zxj':
  ensure => present,
  gid    => 1001,
  uid    => 1001,
  home   => '/home/zxj',
  shell  => '/bin/tcsh',
  managehome => true,
  password => 123456,
}
# puppet apply test.pp
# tail /etc/passwd | grep zxj
zxj:x:1001:500::/home/zxj:/bin/tcsh


     ###注意password最好使用openssl passwd -1 -salt `openssl rand -hex 4`生成密码串


4、 cron

         管理定义周期性任务

         常用属性:

            ensure:目标状态  present,absent

            command:命令或脚本

            environment:运行时的环境变量

            hour       :时

            minute     :分

            month      :月

            monthday   :日

            weekday    :周

            name       :名称

            user       :用户



# vim  test1.pp
cron {'ntpdate':
     ensure => present,
     command => '/usr/sbin/ntpdate time.windows.com &> /dev/null',
     minute => '*/3',
}
# puppet apply test1.pp
# crontab -l
*/3 * * * * /usr/sbin/ntpdate time.windows.com &> /dev/null


5、group

      管理系统上的组

      常用参数

      ensure:目标状态,present,absent

      name  :组名

      gid   : GID

      system :系统组


# vim  test2.pp
group { 'zxj':
     ensure => present,
     name   => zxj,
     gid    => 1001,
}
# puppet apply test2.pp
# tail /etc/group | grep zxj
zxj:x:1001:


6、exec

       执行命令,通常在不得不用时才使用,慎用,通常用于完成puppet自身无法完成的功能

       常用参数

       command:要执行的命令,通常为命令的完整路径

       path : 命令搜索路径

       group:执行命令的组

       user : 执行命令的用户

       onlyif:0,表示仅在命令的状态返回值为0时才执行此命令

       refresh:定义接受的其他资源的通知时,则需要重新执行此命令

       refreshonly:仅当被依赖的额资源发生改变时才被触发

       tries:尝试次数,默认为1

       try_sleep :多次尝试之间的时间间隔


# vim  test3.pp
exec {'mkdir':
     command =>'mkdir /tmp/test',
     path    =>'/bin:/sbin:/usr/bin:/usr/sbin',
}
# puppet apply test3.pp
# ls -l /tmp/
total 4
drwxr-xr-x 2 root root 4096 Apr  7 06:56 test


7、file

        管理文件、目录、软链接;生成文件内容;管理文件权限属性;也可以通过source属性到指定位置下载文件;通过recurse属性来获取目录。

        常用参数

        backup:通过filebacket资源来备份文件,值通常为filebacket资源的名称

        content:文件内容,生成方式有三种(content,source,target)三者彼此互斥

        source :通过指定的ur下载文件至本地,获取文件格式为

                puppet:///modules/MODULE_NAME/file_names

        target : 为符号链接指定目标

        links  :文件为符号链接,值为“follow”,“manage”

        path  :文件路径,必须使用双引号

        mode  :定义权限,通常为8进制数字

        owner :定义文件的属主

        group :定义文件的属组

        force :强制执行删除文件、链接或目录,仅用于ensure为absent时

        purge :清除指定目录存在的,但未在资源中定义的文件

        resurce:目录递归,值为true,false,inf,remote

        replace:替换,本地存在的文件与资源中指定的文件内容不同时是否执行替换,默认为否


# vim  test4.pp
file {'fstab.link':
     ensure => present,
     target => '/etc/fstab',
     links  => 'follow',
     path   => "/tmp/fstab.link"
}
# puppet apply test4.pp
notice: /Stage[main]//File[fstab.link]/ensure: created
notice: Finished catalog run in 0.02 seconds
# ls -l /tmp
-rw-r--r-- 1 root root    0 Apr  7 07:07 fstab.link


8、notify

     调试输出

     常用参数

       message: 信息

       name   : 信息名称


资源引用


     Type['title]


         例如 Package['nginx']

     注意:资源类型首字母一定要大写


元参数metaparams

      用于定义资源间的依赖关系,及应用次序;通知机制    

      特殊属性

1)require (需要依赖于某资源)



service {'nginx':
        ensure  =>true,
        enable  =>true,
        name    =>name,
        require =>Package['nginx'],
}
package {'nginx':
         ensure =>present,
         name   =>nginx,
}
###nginx服务,依赖于nginx安装包先安装完毕。


2)before  (在哪个资源之前)


service {'nginx':
        ensure  =>true,
        enable  =>true,
        name    =>nginx,
}
package {'nginx':
        ensure  =>present,
        name    =>nginx,
        before  =>Service['nginx'],
}
####nginx的安装包在nginx服务启动之前安装


3)notify (通知某资源)



file {'/tmp/test1.txt':
      ensure  =>file,
      content =>"hello puppet",
      notify  => Exec['monitor'],
}
exec {'monitor':
       command =>'echo "/tmp/test1.txt changed." >> /tmp/monitor.txt',
       refreshonly =>true,
       path    => '/bin:/sbin:/usr/bin:/usr/sbin',
}


4)subscribe 订阅 (订阅某资源,即在某资源存在或者改变后再订阅)



service  {'nginx':
         ensure   =>true,
         enable   =>true,
         name     =>nginx,
         subscribe =>Package['nginx'],
}
package  {'nginx':
         ensure   =>present,
         name     =>nginx,
}


5)当资源出现链状关系时如何处理


package {'nginx',
         ensure =>present,
} ->
service {'nginx',
         ensure => ture,
         enable => ture,
}
->表示后边的资源依赖于当前的资源


   其中还有一个~> 表示前资源发生改变后通知后边的资源


puppet的变量


   puppet的变量名称以"$"开头,赋值操作符为"=",应合变量值为"" ,或者什么都不写


   1、puppet的变量可以接受的数据类型

        ###puppet语言支持多种数据类型以及用于变量和属性的值,以及函数的参数

      1)字符型

         非结构化的文本字符串,可以使用引号,也可以不用;

         单引号中的变量不会替换,而双引号中的能够进行变量替换;

         字符型值也支持使用转衣符;

      2)数值型

         可为整数或浮点数,不过puppet只有在数值上下文才把数值当数值型对待

         其他情况下一律以字符型处理


      3)数组

         数组值为中括号"[]"中的逗号分隔的项目列表,最后一个项目后边可以有逗号;

         数组中的元素可以为任意可用数据类型,包括hash或其他数组;

         数组索引为从0开始的证书,也可以使用负数索引;


      4)布尔型

         true和false ,不能加引号;

         if语句的测试条件和比较表达式都会返回布尔型值;

         另外,其他数据类型也可以自动转换为布尔型,如空字符串为false等;


      5)undef

          从未被生命的变量的值类型即为undef;

          也可手动为某变量赋予undef值,即直接使用不加引号的undef字符串;


      6)hash

       即为外键值数据类型,键和值之间使用"=>"分隔,键值对儿定义在"{}",彼此间以逗号分隔;

       其键为字符型数据,而值可以为puppet 支持的任意数据类型;

       访问hash类型的数据元素要使用"键"当作索引进行


    2、puppet的变量类型

       1)自定义变量

       2)facter变量

        #facter -p 可以列出所有的faceter变量

       3)内置变量


         agent: $environment,$clientcert,$clinetversion

         master:$serverip, $servername,$serverversion

    3、正则表达式

       属于puppet的非标准数据类型,不能赋值给变量,仅能用于有限的几个接受正则表达式的地方,即接受使用"=~" 及"!~"匹配操作符的位置,通常包括case语句中的selector,以及节点名称匹配的位置;它们不能传递给函数或用于资源属性的定义;


      puppet中的正则表达式支持使用(?<ENABLED OPTION>:<SUBPATTERN>)和(?-《DISABLED OPTION>:<SUBPATTERN>)两个特殊的符号


      例如下面的示例表示做正则表达式匹配时启用选项"i"(忽略字符大小写),但不支持使用"m"(把.当作换行符)和"x"(忽略模式中的空白字符和注释)



$package = $opratingsystem ? {
    /(?i-mx:ubuntu|debian)/    => 'apache2',
    /(?i-mx:centos|fedora|redhat)/ => 'httpd',
}




puppet表达式



Comparison Oprators
   == (equality)
   != (non-equality)
   <  (less than)
   >  (greater than)
   <= (less than or equal to)
   >= (greater than or equal to)
   =~  (regex match)
   !~  (regex non-match)
   in
Boolean Operators
   and
   or
   !(not)
Arithmetic Operators
   + (addintion)
   - (subtraction)
   / (division)
   *  (multiplication)
   << (left shift)
   >> (right shift )





puppet条件判断


1、if


if  statement  ----if  语句
单分支:
    if CONDITION {
        statment
        ...
     }
双分支
    if CONDITION  {
       statment
       ...
    }
    else {
       statment
       ...
    }
多分支
    if  CONDITION  {
       statment
       ...
    }
    elsif CONDITION {
       statment
       ...
    }
    else {
       statment
       ...
    }


    例1


if  $opratingsystem =~ /^(?i-mx:(centos|redhat|fedora))/ {
     notice ("Welcome to $1 linux")
}

    例2


if $operatingsystem  == 'centos' {
       notify {'centos':message => "Welcome to CentOS linux",}
}elsif $operatingsystem == 'RedHat' {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
       notify {'redhat': message=> "Welcome to RedHat linux",}
}elsif $operatingsystem == 'Fedora' {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
       notify {'fedora': message=> "Welcome to Fedora linux",}
}else {
       notify {'unknown': message => "Unknown Opreating System",}
}


2、case语句



case $operatingsystem {
 'Solaris':   {notice("Welcome to Solaris")}
 'RedHat','CentOS': {notice ("Welcome to RedHat OSFamily")}
  default:     {notice("Welcome,alien*_*")}
}


3、selectors语句



语法格式
CONTROL_VARIABLE ? {
  case1 => value1
  case2 => value2
  ...
  default => valueN
}


   例


$webserver = $operatingsystem ? {
    /^(?i-mx:centos|fedora|redhat)/ => 'httpd/,
    /^(?i-mx:ubuntu|debian)/        => 'apache2',
}
$webprovider = $operatingsystem ? {
    /^(?i-mx:cenotos|fedora|redhat)/ => 'yum',
    /^(?i-mx:ubuntu|debian)/         => 'apt',
}
package {"$webserver":
        ensure => present,
        provider => $webprovider,
}


puppet中的类


   Classl是用于通用目标或目的一组资源,因此它是命令的代码块,在某位置创建之后可以在puppet全局使用。类似于其他编程语言中的类的功能,puppet的类可继承,也可以包含子类,定义类的语法

   class my_class {

         ...puppet code ...

   }


   例如:定义一个名叫nginx的类,其中包含两个类资源,一个是package类型的nginx,一个是service的nginx

   class nginx {

   package {'nginx':

         ensure   => present,

          name    => nginx,

   }

   service {'nginx':

         ensure    =>true,

         enable    =>true,

         subscribe =>Package['nginx'],

   }

   }

   注意:类的名称只能以小写字母开头,可以包含小写字母,数字和下划线。


类的声明

    在manifest文件中定义的类不会直接被执行 ,他们需要事先声明后才能 被执行。

    要声明一个类需要借助include函数,也可以像声明一个资源一样声明类class {'class_name'}

    例如:


# vim  test.pp
class nginx {
    package {'nginx':
          ensure   => present,
           name    => nginx,
    }
    service {'nginx':
          ensure    =>true,
          enable    =>true,
          subscribe =>Package['nginx'],
    }
}
include nginx


# puppet apply test.pp 应用一个类即可



带参数的类

   在定义带参数的类时,需要将参数声明在类名后的小括号"()"中,建议参数有默认值,如果使用多个参数,需要使用逗号分隔。

   在类传递参数时,其方式类似于定义资源的属性

   class {'class_name':

         params1 => value1,

         params2 => value2,

   }


类的继承调用


   类可以基于父类调用,调用时,应该指定通过inherits调用父类



class nginx {
package {'nginx':
       ensure => present,
       name   => nginx,
}
}
class nginx::web inherits nginx {
service {'nginx':
       ensure  =>true,
       enable  =>true,
}
}
include nginx::web

    =>  在子类中覆盖父类中的资源

    +>  在子类中为父类中的资源新增额外的属性


PS:总结也许不全面,不足之处请之处!