puppet

    puppet采用C/S星状的结构,所有的客户端和一个或几个服务器交互。每个客户端周期的(默认半个小时)向服务器发送请求,获得其最新的配置信息,保证和该配置信息同步。每个puppet客户端每半小时(可以设置)连接一次服务器端, 下载最新的配置文件,并且严格按照配置文件来配置客户端. 配置完成以后,puppet客户端可以反馈给服务器端一个消息. 如果出错,也会给服务器端反馈一个消息.

    ~]# puppet descript [-s|--short] [-p|--providers] [-l|--list] [-m|--meta] [type]     //使用查询
    	-l:列出所有资源类型
    	-s:显示指定类型的简要帮助信息
    	-m:显示指定类型的元参数
    
    Usage: puppet [subcommand] [options] [action] [options]	
    
  • agent
  • ca:管理本地CA
  • apply:在本地运行清单
  • catalog:查看catalog文件
  • config:交互完成puppet配置
  • 关系元参数:before/require
    • A before B: B依赖于A
    • B require A: B依赖于A
    package {'nginx':
            name    =>      'nginx',
            ensure  =>      latest,
    #       before  =>      Service['nginx']
    需要事先定义package资源,而且该资源必须是服务所依赖的资源,在
    }
    
    service {'nginx':
            name    =>      'nginx',
            enable  =>      true,
            require =>      Package['nginx']
    表示需要依赖上面的package才能运行service.
    }
    

    在引用时,资源的首字母必须大写,如:

    Type['title']   如  Service['nginx']
    

  • notify和subscribe:都是触发的意思
  • file {'/tmp/test':
            name    => '/tmp/test',
            ensure  => file,
            content => 'Hello World',
    #	notify	=> Exec['monitor']
    每一次应用都会触发Exec['monitor']
    }
    
    exec {'monitor':
            name    => 'monitor',
            command => 'echo "/tmp/test has changed" >> /tmp/change',
            subscribe => File['/tmp/test'],
    此处不写refresh,其也是可以执行的
            refreshonly => true,
    file每被应用一次,其就会往monitor中写入相应的文件。若加入此句refreshonly=true,其会只在file资源改变时写入内容(触发exec)
            path    => '/bin:/sbin:/usr/bin'
    }
    
    
  • 资源的状态链依赖定义:
  • package {'nginx':
            name    => 'nginx',
            ensure  => latest,
    } -> 
    
    file {'/etc/nginx/nginx.conf':
            path    => '/etc/nginx/nginx.conf',
            source  => '/root/puppet/nginx.conf',
    } ->
    
    service {'nginx':
            ensure  => true,
            enable  => true,
    }
    
    Package['nginx'] -> File['/etc/nginx/nginx.conf'] ~> Service['nginx']
    ->:用于定义次序链,即nginx安装之后才会处理配置文件
    ~>:用户定义通知链,配置文件处理好了之后会通知服务
    也可以在定义资源时直接定义
    
    1. 参数简介:
      1. group:Manager groups
    • name:组名
    • gid:GID
    • ensure:目标状态,present/absent
    • system:是否为系统组
    • members:成员用户

  • user:Manager user
    • name:用户名
    • uid,gid,comment,expiry,shell,system,home
    • ensure:present/absent
    • password:加密后的密码串
    • 可用此生成密码:openssl passwd -1 -salt `openssl rand -hex 4`

    group {'mysqll':
            ensure  => present,
            gid     => 1200,
    } ->
    
    user {'ming':
            name    => "ming",
            ensure  => present,
            uid     => 1200,
            groups  => 'mysqll',
            home    => "/home/dai",
            password => '$1$ce1a71ce$c05P/h2f9bwImXX0WILlU0',
            shell   => "/bin/bash",
            comment => "You is my creat",
    }
    

  • package:
    • provider:rpm,yum
    • ensure:installed,present,latest,absent,purged
    • name:包名
    • source:程序包来源,仅对不会自动下载相关程序包的provider有用,例如rpm或dpkg
    package { 'nginx':
            provider => yum,
            name    => 'nginx',
            ensure => latest
    }
    

  • service
    • ensure:true或false表示启动或关闭
    • enable:true或false是否开机自动启动或不自启动
    • path:脚本的搜索路径,默认为/etc/init.d/
    • restart:通常用于定义reload
    • hasrestart:true,false,服务脚本是否支持restart参数
    • hasstatus:属性

  • file
    • ensure:
      • file:类型为普通文件,其内容由content属性生成或复制由source属性指向的文件路径来创建
      • link:类型为链接,必须由target属性指明其链接的目标文件
      • directory:类型为目录,可通过source指向的路径复制生成,recurse属性指明是否递归复制
    • path:文件路径
    • source:源文件
    • content:文件内容,content => template('')
    • target:符号链接的目标文件,当ensure为link时,target表示path指向的文件是一个符号连接文件,其目标为些target属性所指向的路径,此时content和source属性自动失效
    • owner,grouop,mode,atime,ctime,mtime
    file {'/test':
            ensure  => file,
            content => "This is test",
            owner   => 'ming',
            group   => 'mysqll',
            mode    => 777,
    }
    创建文件
    file {'/directory':
            ensure  => directory,
    }
    创建目录
    file {'/test.link':
            ensure  => link,
            target  => '/test'
    }
    创建链接
    
    file {
        "jdk-8u25-linux-x64.rpm":
         ensure  => file,
         path    => '/tmp/jdk-8u25-linux-x64.rpm',
         source  => 'puppet:///modules/jdk8/jdk-8u25-linux-x64.rpm';
        "java.sh":
         ensure => file,
         path    => '/etc/profile.d/java.sh',
         source  => 'puppet:///modules/jdk8/java.sh';
         }
    可传送多个文件,可分开定义,但最后一个条件得是;结尾
    
    

  • exec:
    • command:要运行的命令
    • creates:文件路径,仅此路径表示的文件不存在时,command方才执行
    • user/group:运行命令的用户身份
    • cwd:指定在哪个目录运行命令,如果此目录不存在则运行失败。
    • path:命令path的路径,类似于PATH环境变量
    • onlyif:此属性指定一个命令,此命令正常(退出码为0)运行时,当前command才会运行
    • unless:此属性指定一个命令,此命令非正常退出(退出码为非0)运行时,当前command才会运行
    • refresh:重新执行当前command的替代命令
    • refreshonly:仅接收到订阅的资源的通知时方才运行
    • environment:命令运行时的环境变量,可以直接定义一个path
    exec {'clean log':
            command => "/bin/bash cleanning.sh",
    执行命令的内容
            cwd     => "/usr/local/cripts",
    指定命令在哪个目录下执行
            provider => shell,
            logoutput => true,
    为true时,表示不管命令执行成功与否都输出日志
            onlyif  => "/usr/bin/test `du /var/log/message | cut -f1 -gt 102400`"
    onlyif参数控制了命令执行的条件,如上只有当message文件大小超过100M时,才执行command的参数指定的cleanning.sh脚本
    }
    

    未添加控制参数的exec资源将变得非常危险,因为它会在客户端每次从服务端更新资源时被执行。需要交互的命令一搬都不能执行成功


  • cron:计划任务
    • command:要执行的任务
    • ensure:present/absent
    • hour,minute,monthday,month,weekday
    • user,以哪个用户的身份运行命令
    • target:添加为个哪个用户的任务
    • name: corn job的名称
    cron{'timesync':
    	command => '/usr/sbin/ntpdate 10.1.0.1 &> /dev/null',
    	ensure  => present,
    	minute  => '*/3',
    	user    => 'root',
    }		
    

  • notify:
  • sends an arbitrary message to the agent run-time log.
    • message:信息内容
    • name:信息名称

  • puppet variable:
  • $variable_name=value:引用变量时可以直接 使用或者使用双引号

    作用域:

    • 仅能隔离:变量,资源的默认属性
    • 不能隔离:资源的名称,及引用

    引用路径:

    • 相对路径:$name
    • 绝对路径:$::scope::scope:variable

    变量的赋值符号:

    • =
    • +=
    数据类型:
    • 字符型:引号可有可无,但单引号为强引用,双引号为弱引用
    • 数值型:默认均识别为字符串,仅在数值上下文才以数值对待
    • 数组:[]中以逗号分隔元素列表,从0开始,也可以用下标为-1,-2..意思是从右边开始的第一个,第二个
    • 布尔型值:true,false不能加引号
    • hash:{}中以逗号分隔k/v数据列表:键为字符型,值为任意puppet支持的类型,访问hash类型的数据元素要使用“键”当做索引进行:
    • { 'mon' => 'Monday', 'tue' => 'Tuesday'};
    • undef:未定义
    正则表达式: OPTIONS:
    • i:忽略字符大小写
    • m:把.当换行符
    • x:忽略中的空白字符
    • (?i-mx:PATTERN),不能赋值给变量,仅能用在接受=~或!~操作符的位置。-mx就是表示不使用m和x

  • 流程控制语句:
    1. if语句:
    2. if CONDITION {
      	....
      } else {
      	....
      }
      
      CONDITION的给定方式:变量,比较表达式,有返回值的函数
      
      ex:
      
      if $osfamily =~ /(?i-mx:(debian|ubuntu))/ {
      	$webserver = 'apache2'
      } else {
      	$webserver = 'httpd'
      }
      
      package {"$webserver":
              ensure  => latest,
      }
      
      file {'httpd.conf':
              path    => '/etc/httpd/conf/httpd.conf',
              source  => '/root/puppet/httpd.conf',
              ensure  => file,
              require => Package["$webserver"],
      #       notify  => Service['httpd']
      }
      
      service {'httpd':
              ensure  => true,
              enable  => true,
              restart => 'systemctl restart httpd.service',
              subscribe => File['httpd.conf']
      }  只要当配置文件发生改变时,才会触发重启
      
      

    3. case语句:
    4. case CONTROL_EXPRESSION {
      	case1: { ... }
      	case2: { ... }
      	case3: { ... }
      	default: { ... }
      }
      
      CONTROL_EXPRESSION:变量,表达式,有返回值的函数
      各case的给定方式:直接字符串,变量,有返回值的函数,正则表达式模式,default
      
      
      ex:
      
      case $osfamily {
      	"Redhat": { $webserver='httpd' }
      	/(?i-mx:debian)/: { $webserver='apache2' }
      	default: { $webserver='httpd'}
      }
      
      
    5. selector语句:
    6. CONTROL_VARIABLE ? {
      	case1 => value1,
      	case2 => value2,
      	...
      	default => valueN,
      }
      CONTROL_VARIABLE的给定方法:变量,有返回值的函数
      各case的给定方式:直接字符串,变量,有返回值的函数,正则表达式模式,default
      注意:不能使用列表格式,但可以是其它的selector
      ex:
      $pkgname = $operatingsystem ? {
      	/(?i-mx:(unbuntu|debian))/	=> 'apache2',
      	/(?i-mx:)(redhat|defora|centos))/	=> 'httpd',
      	defautl => 'httpd'
      
      }
      
      package{"$pkgname":
      	ensure	=> installed,
      }
      
      


  • 类:
  • 为了实现通用目标或目的组织在一起的一个或多个资源,即命名为代码块

    • 类在某位置创建之后可在puppet全局使用
    • puppet的类可以继承,也可以包含子类
    • 类的名称只能小写字母开头,可以包含小写字母,数字和下划线
    • 每个类都会引入一个新的变量scope,这意味着在任何时候访问类中的变量时,都得使用其完全限定名称,如${nginx::params::name}

    类的分类:

    • 不带参数的类:可通过include或资源的方式进行声明使用
    • 带参数的类:同一个类在不同的OS上可能会略有不同,因此需要通过获取相应系统的fact来实现有区别对待。然而,万一相应的OS没有输出类所期望的fact或者是类依赖于非fact因素时,此机制将无法满足需求。此时就需要使用带参数的类来完成此类功能,同时在声明类时为其参数传递相应的值即可完成功能。只能使用资源式的声明方式

    调用方式:

    1. include CLASS_NAME1,CLASS_NAME2,...
    2. class{'CLASS_NAME': attribute => value, }

    类的声明方式一:

    class apache2 {
            $webserver = $operatingsystem ? {
                    /(?i-mx:(centos|redhat|fedora))/        => 'httpd',
                    /(?i-mx:(ubuntu|debian))/       => 'apache2',
                    default => 'httpd'
            }
    
            package {'httpd':
                    ensure  => latest,
                    before  => File['httpd.conf']
            }
    
            file {'httpd.conf':
                    ensure  => file,
                    path    => '/etc/httpd/conf/httpd.conf',
                    source  => '/root/puppet/httpd.conf',
                    notify  => Service['httpd']
            }
    
            service {'httpd':
                    ensure  => true,
                    enable  => true,
                    restart => 'systemctl restart httpd.service',
            }
    }
    include apache2
    直接调用apache2类
    

    类的声明方式二:

    class apache2($webserver='apache2') {
    没有传递参数,将会使用默认httpd参数
            package {"$webserver":
                    ensure  => latest,
                    before  => File['httpd.conf']
            }
    
            file {'httpd.conf':
                    ensure  => file,
                    path    => '/etc/httpd/conf/httpd.conf',
                    source  => '/root/puppet/httpd.conf',
                    notify  => Service['httpd']
            }
    
            service {'httpd':
                    ensure  => true,
                    enable  => true,
                    restart => 'systemctl restart httpd.service',
            }
    }
            class{'apache2':
                    webserver       => 'httpd'
            }
    自定义实例变量结果,并且上变量得有默认值,否则不予执行
    
    

    类的继承:

    通常将公共功能定义为基类,需要增加的功能定义为子类,其继承一个已有的类,并实现覆盖资源属性,或向资源属性追加额外值

    • 声明子类时,其基类会被自动声明
    • 基类成为子类的父作用域,基类中的变量和属性默认值会被子类复制一份
    • 子类可以增加和覆盖父类中同一资源的相同属性
    • 在子类中为父类的资源新增属性或覆盖指定的属性的值
    Type['title'] {
    	attribute	=> value,
    引用并修改
    	...
    }
    
  • 在子类中为父类资源的某属性增加新值
  • Type['title'] {
    	attribute	+> value,
    添加新值
    	...
    }
    
    class apache2($webserver='apache2') {
    #       $webserver = $operatingsystem ? {
    #               /(?i-mx:(centos|redhat|fedora))/        => 'httpd',
    #               /(?i-mx:(ubuntu|debian))/       => 'apache2',
    #               default => 'httpd'
    #       }
    
            package {"$webserver":
                    ensure  => latest,
                    before  => File['httpd.conf']
            }
            service {'httpd':
                    ensure  => true,
                    enable  => true,
                    restart => 'systemctl restart httpd.service',
            }
    }
    
    class apache2::web inherits apache2 {
    子类继承父类的方式如上:父类::子类 inherits 父类
            Service['httpd'] {
                    subscribe => File['httpd.conf']
            }
    
            file {'httpd.conf':
                    ensure  => file,
                    path    => '/etc/httpd/conf/httpd.conf',
                    source  => '/root/puppet/httpd.conf',
                    notify  => Service['httpd']
            }
    }
    
    class {'apache2':
            webserver       => 'httpd',
    }
    
    include apache2::web
    

  • 模板
  • 基于ERB(扩展ruby语言)模板语言,在静态文件中使用变量等编程元素生成适用于多中不同环境的文本文件(配置文件),主要用于实现在文本文件中嵌入ruby代码,原来的文件信息不会被改变,但ruby代码会被执行,执行结果将直接替换原来代码

    模板代码的添加方式:

    • <%= ruby expression %>:替换为表达式的值
    • <% ruby expression %>:仅执行代码,而不替换
    • <%# comment %>:文本注释
    • <%- rubycode %>:忽略空白字符
    • <% rubycode -%>:忽略空白行
    • 还有判断语句,请参考官方文本链接

    其它更多添加方式请参考官方文档:

    https://docs.puppet.com/puppet/latest/lang_template_erb.html

    在模板文件中可以使用变量,包括puppet的任意可用变量,但变量名需以@开头。.erb可用可不用,在配置文件后加.erb只是为了好分辨

    ~]# mv nginx.conf nginx.conf.erb
    ~]# vim nginx.conf.erb
    worker_processes <%= @processorcount %>
    
    class nginx {
            package {'nginx':
                    provider => yum,
                    ensure  => latest,
            }
    }
    
    class nginx::web inherits nginx {
            file {'nginx':
                    ensure  => file,
                    content => template('/root/puppet/nginx.conf.erb'),
    如果定义好配置文件,使用了ERB的配置语法,文件复制不能用source,而是需要使用content参数,利用template函数生成对应的配置文件,此为固定格式用法(将使用template函数生成文本内容,再导入至对应的配置文件)
                    path    => '/etc/nginx/nginx.conf',
                    require => Package['nginx'],
                    notify  => Service['nginx']
            }
    
            service {'nginx':
                    ensure  => true,
                    enable  => true,
                    restart => 'systemctl reload nginx.service',
                    subscribe => File['httpd.conf']
            }
    }
    include nginx::web
    

  • 模块目录:
    • ~]# tree /nginx/
      /nginx/
      ├── files
      ├── lib
      ├── manifests
      │   └── init.pp
      ├── spec
      ├── tempaltes
      │   └── nginx.conf.erb
      └── tests
      
    • /etc/puppet/modules/:模块存放的默认路径,在此目录下建立相应的模块目录即可
    • modue_name:模块名称
    • manifests:资源清单目录
    • init.pp:默认的资源定义文件,此文件必须存在
    • files:静态配置文件存放路径
    • puppet URL: puppet:///modules/MODULE_NAME/FILE_NAME

    • templates:erb模块配置文件存放路径,其文件结束后缀为.erb
    • lib:插件目录
    • tests:当前模块的使用帮助文件及示例文件
    • spec:类似于tests目录,存储lib目录下定义的插件的使用帮助和示例文件
    • 模块管理工具

      • puppet help module:获取puppet module的帮助信息
      • USAGE: puppet module <action> [--environment production ]
      • install:到puppet forge中心去安装
      • list:查看已安装的模块
      • search:到forge中心搜索模块
      • uninstall:卸载模块
      • upgrade:更新模块

      注意:puppet3.8以后的版本中,资源清单文件名要与文件类名保持一致,例如某子类名为“nginx::web”,其文件名应该为web.pp。不在支持 import

      ~]# puppet apply -d -v -e 'include classes' --noop array
      此处的-e后得是模块名,也就是在/etc/puppet/modules/下的模块名
      

    • Master/Agent模式
      1. master/agent工作原理:
      2. master/agent强依赖于DNS服务(证书签署是对FQDN做证书颁发的),由master端定义好功能模块,再到/etc/puppet/manifests/定义site.pp文件,定义站点所需要的资源。master端通过自建CA并签发证书给各站点,使用证书验证客户端的身份,当站点发出请求时Master端将查找site.pp文件中定义的资源,编译成catalog,发送给客户端。 agent默认每隔30分钟向Master发送node_name和facts,并请求catalog,在本地执行catalog代码。master(监听8140端口)与agent(监听在8139)二者之间基于https协议通信,其远程过程调用方式为xmlrpc机制。

      3. 安装软件包:
      • master:yum install puppet puppet-server facter
      • agent:yum install puppet facter
    • /etc/puppet/puppet.conf配置文件
      • [main]:应用于server端和agent端,都会生效
      • [agent]:应用于agent端生效
    • puppet cert命令,证书管理工具
      • Usage: puppet cert <action> [-h | --help]
      • clean node_name:清除node_name节点的证书
      • list:查看未签署的证书请求
      • list -all:查看所有证书
      • sign "node_name":对node_name签署证书
      • sign -all:签署所有请求
      • verify:检验

    • 在puppet-sever主机查看初始化过程并了解工作过程
    • ~]# puppet master --no-daemonize -v 详细的初始化过程
      Info: Creating a new SSL key for ca   生成一个私钥
      Info: Creating a new SSL certificate request for ca 生成一个证书请求
      ...
      Notice: Signed certificate request for ca自签证书
      Info: Creating a new certificate revocation list 生成吊销列表
      Info: Creating a new SSL key for localhost
      Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
      Info: Creating a new SSL certificate request for localhost
      ...
      Notice: localhost has a waiting certificate request
      Notice: Signed certificate request for localhost
      ...CertificateRequest localhost at '/var/lib/puppet/ssl/ca/requests/localhost.pem'
      ...CertificateRequest localhost at '/var/lib/puppet/ssl/certificate_requests/localhost.pem'
      Notice: Starting Puppet master version 3.6.2
      

    • 在agent端也查看第一次启动并向master端的工作动作(puppet agent --test):
    • ~]# puppet agent --server master --no-daemonize -v 引处的server用的主机名称,主机名不会变,ip地址会变,做实验我就直接写在/etc/hosts文件里的
      Info: Creating a new SSL key for node6.iofunction.com
      Info: Caching certificate for ca
      Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
      Info: Creating a new SSL certificate request for node6.iofunction.com
      ...
      创建一个证书签署请求发往master端,等待签署完成的证书
      

    • master/agent配置实例
    • 1、配置master端
      ~]# puppet master --no-daemonize -v #首次以前台模式启动,确认无误再运行为后端
      ~]# systemctl start puppetmaster.service
      ~]# systemctl enable puppetserver.service
      ~]# ss -tnlp : 8140/tcp
      
      2、定义站点配置文件
      # cd /etc/puppet/manifests/
      # vim site.pp  #必须先为站点定义好站点文件,不然agent端启动时会报错
      node /^centos7.pc\d+/ {
          include nginx::webserver
      }
      
      3、配置agent端(发送证书签署请求给Master)
      # puppet agent --server=master_hostname --no-daemonize --noop --test -v #建议首次启动时以前台模式运行,确认OK后,再将运行为后端
      ~]# systemctl start puppetagent.service
      
      
      4、在master端为客户端签署证书
      ~]# puppet cert list #首先查看未签署的证书列表
      ~]# puppet cert sign node_name 
          或者
      ~]# puppet cert sign -all
      
      5、以守护进程方式启动agent
      ~]# systemctl start puppet
      
      ####必要是清除客户端请求
      ~]# puppet cert list -all : 查看已经签署的客户端证书
      ~]# puppet cert clean node_name : 清除一个Node的签署证书
      
      rm -rf /var/lib/puppet/ssl : 移除ssl证书
      
      
    • 推送消息:
    • ~]# puppet help kick   虽然要被弃用了,但还是有人在用
      puppet kick [-a|--all] [-c|--class <class>] [--host <host>]
      
      agent端:
      ~]# vim /etc/puppet/puppet.conf
      [main]
      ...
      listen = true
      [agent]
      server = master 
      master是谁
      
      ~]# tail -10 /etc/puppet/auth.conf
      path /run
      method save
      auth any
      allow master.iofunction.com
      允许主像agent推送消息
      # deny everything else; this ACL is not strictly necessary, but
      # illustrates the default policy.
      path /
      auth any
      
      
    • 创建site.pp文件
    • site.pp文件是puppet读取所有模块pp文件的开始

      ~]# vim /etc/puppet/manifests/site.pp
      node /^node\d+\.iofunction\.com/ {   主机名匹配
              include chrony, jdk8
      类名同module名相同,方可执行
      }
      

      相关文章: