puppet: OS Provisioning(PXE,Cobbler) OS Configuration(ansible,puppet,saltstack,chef,cfengine) Command and Control(func,ansible,fabric)

puppet:IT基础设施自动化管理工具
	整个生命周期
		provisioning
		configuration
		orchestration
		reporting

	www.puppetlabs.org

	作者:Luke Kanies,PuppetLabs公司

puppet::agent
	master/agent
		master:puppet server
		agent:
			真正执行相应管理操作的核心部件,周期性地去master请求与自己相关的配置

puppet的工作模式:
	声明性,基于模型
		定义:使用puppet配置语言定义基础配置信息
		模拟:模拟测试运行
		强制:强制当前与定义的目标状态保持一致
		报告:通过puppet api将执行结果发送给接受者

puppet有三个层次:
	configuration language(配置语言)
	transactional layer(事务层)
	resource abstraction layer(资源抽象层)

安装: agent:puppet,factor master:puppet-server 是ruby语言研发的,所以需要ruby的环境 需要软件: facter-2.4.1-1.el7.x86_64.rpm puppet-3.8.4-1.el7.noarch.rpm puppet-server-3.8.4-1.el7.noarch.rpm

安装生成文件:
	/usr/lib/systemd/system/puppet.service:作为服务运行的文件
	/usr/bin/puppet:程序文件
	/etc/puppet/puppet.conf:puppet的配置文件

	puppet命令:
		命令用法格式:
			puppet <subcommand> [options] <action> [options]

			puppet describe -l:列出所有的支持类型
			puppet describe RESOURCE_TYPE(资源类型):列出资源类型的详细格式

		资源抽象:

   puppet 从以下三个维度来对资源完成抽象 相似的资源被抽象成同一种资源**“类型”** ,如程序包资源、用户资源及服务资源等 将资源属性或状态的描述与其实现方式剥离开来,如仅说明安装一个程序包而不用关心其具体是通过yum、pkgadd、ports或是其它方式实现 仅描述资源的目标状态,也即期望其实现的结果,而不是其具体过程,如“确定nginx 运行起来” 而不是具体描述为“运行nginx命令将其启动起来” 这三个也被称作puppet 的资源抽象层(RAL)    RAL 由type( 类型) 和provider( 提供者,即不同OS 上的特定实现)组成

	资源定义:
	  资源定义通过向资源类型的属性赋值来实现,可称为资源类型实例化
	  定义了资源实例的文件即清单,manifest
	  定义资源的语法如下:
			type {'title':
					attribute1 	=> value1,
					atrribute2	=> value2,
					……
				}
		注意:type必须使用小写字符;title是一个字符串,在同一类型中必须惟一;每一个属性之间需要用“,”隔开,最后一个“,”可省略

   例如,可以同时有名为nginx 的“service”资源和“package”资源,但在“package” 类型的资源中只能有一个名为“nginx”的资源 puppet resource命令可用于交互式查找及修改puppet资源

		常用资源类型:
			user,group,file,package,service,exec,cron,notify(通知)

		group:
			管理组资源
			常用属性:
				name:组名,NameVar
				gid:GID
				system:true,false
				ensure:present,absent
				members:组成员
		user:
			管理用户
			常用属性:
				comment:注释
				ensure:present,absent,role(角色)
				expiry:过期时间
				gid:基本组
				groups:附加组
				home:家目录
				name:用户名,NameVar
				password_max_age:密码最大使用期限
				password_min_age:密码最小使用期限
				purge_ssh_keys:是否为该用户清除授权的SSH密钥,值有false和true
				salt:生成密码时的盐
				shell:默认的shell
				system:是否为系统用户,true|false
				password:密码
		file:
			管理文件及其内容,从属关系以及权限,内容可通过content属性直接给出,也可通过source属性根据远程服务器路径下载生成
			指明文件内容来源:
				content:直接给出文件内容,支持\n和\t等符号
					file { "/etc/resolv.conf":
			               content => "$str",
			             }
				source:从指定位置下载文件
				ensure:file,directory,link,present,absent
			常用属性:
				checksum:使用哪种算法校验文件完整性
				recurse:如果文件是目录时使用
				force:强制运行,可用值yes,no,true,false
				group:属组
				owner:属主
				mode:权限,支持八进制格式权限,以及u,g,o的赋权方式
				mtime:最近一次修改时间
				path:目标路径
				recurselimit:最多支持几级目录
				replace:是否替换本地已经存在的文件或符号链接
				source:源文件路径,可以是本地文件路径(单机模型),也可以使用puppet:///modules/module_name/
					file { "/etc/nfs.conf":
				             source => [
				             "puppet:///modules/nfs/conf.$host",
				             "puppet:///modules/nfs/conf.$operatingsystem",
				             "puppet:///modules/nfs/conf"
				           ]
				          }
				target:当ensure为link时,target表示path指向的文件是一个符号链接文件,其目标为此target属性指向的路径
				此时content和source属性自动失效
					file {'/tmp/mydir':
					        ensure  => directory,
					}       

					file {'/tmp/puppet.file':
					        content => 'puppet testing\nsecond line.',
					        ensure  => file,
					        owner   => 'centos',
					        group   => 'distro',
					        mode    => '0400'
					}

					file {'/tmp/fstab.puppet':
					        source  => '/etc/fstab',
					        ensure  => file,
					}

					file {'/tmp/puppet.link':
					        ensure  => link,
					        target  => '/tmp/puppet.file',
					}

		exec:运行--外部命令:命令应该具有幂等性
			幂等性:
				1.命令本身具有幂等性
				2.资源有onlyif,unless等属性以实现命令的条件式运行
				3.资源有refreshonly属性,以实现只有订阅的资源发生变化时才执行
			常用属性:
				command:运行的命令:NameVar
				creates:此属性指定的文件不存在时才执行此命令
				cwd:运行命令的目录
				environment:想要为其设置的任何其他环境变量命令,将覆盖path属性
				user:以指定用户身份运行命令
				group:以指定组身份运行命令
				onlyif:给定一个测试命令,仅在此命令执行成功(返回状态码为0)时才运行command指定的命令
				path:用于命令执行的搜索路径,其值通常为列表['path1','path2',...],如果不定义此属性,则需要给定命令的绝对路径
				unless:给定一个测试命令,仅在此命令执行失败(返回状态码不为0)时才运行command指定的命令
				refresh:接收到其他资源发来的refresh通知时,默认是执行exec定义的command指定的命令,但是refresh可以改变这种行为,即可指定仅在refresh时运行的命令
				refreshonly:仅在收到refresh通知,才运行此资源
				returns:期望的返回值,只有返回这个定义的返回值才认为command执行成功
				timeout:多久执行命令超时
				tries:重试执行命令的次数
					实例:
						exec {'/usr/sbin/modprobe ext4':
						        user    => root,
						        group   => root,
						        refresh => '/usr/sbin/modprobe -r ext4 && /usr/sbin/modprobe ext4',
						        timeout => 3,
						        tries   => 2
						}

						exec {'/bin/echo www.baidu.com> /tmp/hello.txt':
						        user    => root,
						        group   => root,
						        timeout => 3,
						        tries   => 2,
						        creates => '/tmp/hello.txt'
						}

						exec {'/bin/echo www.baidu.com> /tmp/hello2.txt':
						        user    => root,
						        group   => root,
						        timeout => 3,
						        tries   => 2,
						        unless  => '/usr/bin/test -e /tmp/hello2.txt'
						}

		notify:
			核心属性:
				message:要发送的消息的内容,NameVar
					notify {'hello there':}

		cron:
			常规属性:
				command:要执行的任务(命令或脚本)
				ensure:目标状态,present/absent
				hour:时
				minute:分
				monthday:日
				month:月
				weekday:周
				user:以哪个用户的身份运行命令(默认为root)
				target:添加为哪个用户的任务
				name:cron job的名称
				environment:运行时的环境变量

		package:
			常规属性:
				configfiles:是否应该保留或替换configfiles,默认为`keep`,有效值是`keep`,`replace`
				ensure:安装方式,installed, present, latest, absent, any version string (implies present)
				install_options:
				status:状态
				source:程序包来源,仅对不会自动下载相关程序包的provider有用,例如rpm或dpkg
				provider:指明安装方式
				name:包名,可以省略,如果省略,将继承title的值
					实例:
						package {'zsh':
							ensure	=> latest,
						}

						package	{'vsftpd':
							ensure	=> installed,
							provider => 'yum',
							name	=> 'vsftpd'
						}

		service:
			常规属性:
				binary:守护进程的路径
				enable:是否开机自启动,有效值为true,false,manual
				ensure:服务的目标状态,值有true(running)和false(stopped)
				hasrestart:
				hastatus:
				name:服务名称,可以省略,如果省略,将继承title的值,即NameVar
				path:服务脚本路径,默认为/etc/init.d/下
				start:定制启动命令(没有start命令时),定义refresh之后的动作
				stop:定制关闭命令(没有stop命令时),定义refresh之后的动作
				restart:定制重启命令,定义refresh之后的动作
				status:定制状态
				manifest:指定配置服务的命令或清单的路径
				pattern:用于搜索此服务相关的进程的模式,当脚本不支持restart/status时,用于确定服务是否处于运行状态
					实例:
						service {'httpd':
							ensure	=> running,
							enable	=> true,
							hasrestart	=> true,
							hasstatus	=> true,
							restart	=> 'systemctl reload httpd.service',
						}
		特殊属性:Metaparameters
			资源引用:
				Type['title']

			依赖关系:
				被依赖的关系中使用:before
				依赖其他资源的资源:require
					-> -> 表示后资源需要依赖前资源,链式依赖
			通知关系:
				被依赖的资源中使用:notify
				监听其他资源的资源:subscribe
					~> 表示前资源变动通知后资源调用,链式通知
				notify:A notify B:B依赖于A,且A发生改变后会通知B;
				subscribe:B subscribe A:B依赖于A,且B监控A资源的变化产生的事件



	资源属性中的三个特殊属性:
	    Namevar:可简称为name
	    	大多数类型的资源都有一个特殊属性,用于在目标系统上识别资源,对应的有一个属性也叫name,所以一般来讲,定义一个资源时如果没给name的话title就成了它的name
	    ensure:资源的目标状态
	    	大多数资源都有的一个属性,用于控制资源的存在性
	    		ensure =>file:存在且为一个普通文件
	    		ensure =>directory:存在且为一个目录
	    		ensure =>present:存在,可通用于上述三种
	    		ensure =>absent:不存在
	    Provider:指明资源的管理接口

puppet(2) master/agent site manifests agent: manifests ==> catalog

puppet的变量及其作用域:
	变量名均以$开头,赋值符号=,任何非正则表达式类型的数据均可赋值给变量

	作用域:定义代码的生效范围,以实现代码间隔离
		仅能隔离:变量,资源的默认属性
		不能隔离:资源的名称,及引用

	正则表达式:
		1.属于puppet的非标准数据类型,不能赋值给变量,仅能用于有限的几个接受正则表达式的地方,即接受使用"=~"及"!~"匹配操作符的位置,通常包括case语句中的selector,以及节点名称匹配的位置
		2.他们不能传递给函数或用于资源属性的定义
		3.puppet中的正则表达式支持使用(?<ENABLED OPTION>:<SUBPATTERN>)和(?-<DISABLED OPTION>:<SUBPATTERN>)两个特殊的符号
			例如下面的示例表示做正则表达式匹配时启用选项"i(忽略字符大小写)",但不支持使用"m"(把.当做换行符)和"x"(忽略模式中的空白字符和注释)
				-i:区分字符大小写
				i:忽略字符大小写

	每个变量两种引用途径:
		相对路径
		绝对路径

	变量的赋值符号:
		=
		+=:追加赋值

	数据类型:
		布尔型:true,false
		undef:未声明
		字符型:可以不用引号,支持单引号(强引用),双引号(弱引用)
		数值型:整数和浮点数
		数组:[item1,item2,...],元素可为任意可用数据类型,包括数组hash,索引从0开始,还可以使用负数
		hash:[key => value,key = value,...],键为字符串,而值可以是任意数据类型

		正则表达式:
			非标准数据类型,不能赋值给变量
				语法结构:
					(?<ENABLED OPTION>:<SUBPATTERN>)
					(?-<DISABLED OPTION>:<SUBPATTERN>)

	表达式:
		比较操作符:==,!=,<,<=,>,>=,=~,!~,in
		逻辑操作符:and,or,!
		算术操作符:+,-,*,/,%,>>,<<

	条件判断:
		if,case,selector,unless

			if语句:
				if condition {
					...
				}

				if condition {
					...
				} else {
					...
				}
					示例:
						if $processorcount>1 {
							notice("SMP Host.")
						}else{
							notice("Poor Guy.")
						}
					CONDITION的用法:
						1.比较表达式
						2.变量引用
						3.有返回值的函数调用

					模式匹配的语句:
						if $operatingsystem =~ /^(?imx:(CentOS|ReadHat))/ {
							notice("Welcome to $1 linux server!")
						}

			case语句:
				case CONTROL_EXPRESSION {
					case1,case2: {statement1}
					case3,case4,case5: {statement}
					...
					default: {statement}
				}

				CONTROL_EXPRESSION:表达式,变量,函数(有返回值)
					case:
						字符串,变量,有返回值函数,模式,default

			selector语句:
				类似于case,但分支的作用不在于执行代码片段,而是返回一个直接值

				CONTROL_VARIABLE ? {
					case1 => value1,
					case2 => value2,
					...
					default => valueN
				}

				CONTROL_VARIABLE:变量,有返回值的函数,但不能是表达式
				case直接值(需要带引号),变量,有返回值的函数,正则表达式模式,default


类:class
	用于公共目的的一组资源,是命名的代码块,创建后可在puppet全局进行调用,类可以被继承
		语法格式:
			class class_name {
				...puppet code...
			}
			注意:
				1.类的名称只能以小写字母开头,可以包含小写字母,数字和下划线
				2.每个类都可以引入一个新的变量scope,这意味着在任何时候访问类中的变量时,都得使用其完全限定名称

			示例:
				class httpd {
				    $webserver=httpd
				    package {$webserver:
					ensure	=> latest,
				    }

				    file {'/etc/httpd/conf/httpd.conf':
					ensure	=> file,
					source	=> '/root/modules/httpd/files/httpd.conf',
					require	=> Package['httpd'],
					notify	=> Service['httpd'],
				    }
				    service {'httpd':
					ensure	=> running,
					enable	=> true,
					hasrestart	=> true,
					hasstatus	=> true,
					#restart	=> 'systemctl reload httpd.service',
					require	=> [Package['httpd'],File['/etc/httpd/conf/httpd.conf']],
					
				    }
				}

			类声明的方式:
				include class_name,class_name,...

			定义能接受参数的类:
				class class_name($arg1='value1',$arg2='value2') {
					puppet code ...
				}

			类声明方式2:
				class {'class_name':
					arg1 => value,
					arg2 => value
				}

				示例:
					class httpd ($webserver='httpd'){
					    package {$webserver:
						ensure	=> latest,
					    }

					    file {'/etc/httpd/conf/httpd.conf':
						ensure	=> file,
						source	=> '/root/modules/httpd/files/httpd.conf',
						require	=> Package['httpd'],
						notify	=> Service['httpd'],
					    }
					    service {'httpd':
						ensure	=> running,
						enable	=> true,
						hasrestart	=> true,
						hasstatus	=> true,
						#restart	=> 'systemctl reload httpd.service',
						require	=> [Package['httpd'],File['/etc/httpd/conf/httpd.conf']],
						
					    }
					}
					include httpd

					class {'httpd':
						$webserver => 'httpd',
					}

	类继承:
		定义方式:
			class base_class {
				... puppet code...
			}
			class base_class::class_name inherits base_class {
				... puppet code ...
			}

		作用:继承一个已有的类,并实现覆盖资源属性,或向资源属性追加额外值
			=>:在子类中覆盖父类中的资源
			+>:在子类中为父类中的资源新增额外的属性

		类继承时:
			(1)声明子类时,其基类会被自动首先声明
			(2)基类成为了子类的父作用域,基类中的变量和属性默认值会被子类复制一份
			(3)子类可以覆盖父类中同一资源的相同属性的值

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

	<%= Ruby Expression %>:替换为表达式的值
	<% Ruby Expression %>:仅执行代码,而不替换
	<%# comment %>:文本注释
	<%%:输出为<%
	%%>:输出为%>
	<%- Ruby code %>:忽略空白字符
	<% Ruby code -%>:忽略空白行

	在模板中可以使用变量,包括puppet的任意可用变量,但变量名以@字符开头

	条件判断:
		<% if CONDITION -%>
			some text
		<% end %>

		<% if CONDITION -%>
			some text
		<% else %>
			some other text
		<% end %>

	迭代:
		<% @ArrayName.echo do| Variable_Name | -%>
			some text <%= Variable_Name %>
		<% end %>

	实例:
		class nginx::proxy inherits nginx {
			file {'/etc/nginx/nginx.conf':
				#source	=> '/root/modules/nginx/files/nginx_proxy.conf',
				content => template('/root/modules/nginx/files/nginx_proxy.conf'),
				ensure	=> file,
				notify	=> Service['nginx']
		}


模块:
	module_name/
		manifests/
			init.pp:至少应该包含一个与当前模块名称同名类,以实现自包含,自装载
		files:静态文件:puppet:///modules/module_name/file_name
		templates:模板文件目录:template('module_name/template_file_name')
		lib:插件目录
		tests:当前模块的使用帮助文件及示例文件
		spec:类似于tests目录,存储lib目录下定义的插件的使用帮助或示例文件


	模块管理命令:
		 puppet module <action> [--environment production ] [--modulepath $basemodulepath ]
		 	ACTIONS:
			  build        Build a module release package.
			  changes      Show modified files of an installed module.
			  generate     Generate boilerplate for a new module.
			  install      Install a module from the Puppet Forge or a release archive.
			  list         List installed modules
			  search       Search the Puppet Forge for a module.
			  uninstall    Uninstall a puppet module.
			  upgrade      Upgrade a puppet module.

puppet(3) agent/master: agent:默认每个30分钟向master发送node name和facts,并请求catalog master:验证客户端身份,查找与其相关的site manifest,编译生成catalog,并发送给客户端

	ssl xmlrpc,https
		8140/tcp

	master:puppet,puppet-server,facter
	agent:puppet,facter

配置文件:
	主配置文件:/etc/puppet/puppet.conf

	显示或设置配置参数:
		puppet config
			print
			set

	手动生成完成配置文件:
		master:
			puppet master --genconfig >/etc/puppet/puppet_default.conf
		agent:
			puppet agent --genconfig

		注意:
			(1)生成新的配置之前不能删除或移动原有的puppet.conf
			(2)生成的配置中,有的参数已经被废弃,与现有puppet版本可能兼容
			(3)有的参数的默认值与现有的版本所支持的值的范围可能不相兼容

	获取puppet文档:
		puppet doc
			分段:称为reference
			列出所有的reference
				puppet doc --list

			查看某一reference
				puppet doc -r reference_name
					例:puppet doc -r type

	配置文件的组成部分:
		[main]
		[master]
		[agent]

	签署证书:
		puppet cert <action> [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose] [--digest <digest>] [<host>]

			action:
				list:查看所有签署请求
				puppet cert sign node2.fang.com:签署请求

	配置agent/master:
		1.配置master
			puppet master --no-daemonize -v
			systemctl start puppetmaster
			systemctl enable puppetmaster
				8140/tcp
		2.配置agent
			puppet agent --server=MASTER_HOST_NAME --no-daemonize --noop --test -v
			puppet agent --server=MASTER_HOST_NAME --no-daemonize --test -v -d
				发送证书签署请求给master
		3.在master为客户端签署证书
			puppet cert list
			puppet cert sign NODE_NAME
			puppet cert sign --all
			puppet cert clean NODE_NAME

		4.在master端
			(1)安装所有要用到的模块
				puppet module install
				自研
			(2)定义site manifest
				在/etc/puppet/mamifests/site.pp
					node 'NODE_NAME' {
						... puppet code ...
					}

					例如:
						node 'node2.fang.com' {
							include nginx::proxy
						}
		节点管理:
			site.pp定义节点的方式
				(1)以主机名直接给出其相关定义
					node 'NODE_NAME' {
						...puppet code...
					}
				(2)把功能相近的主机事先按照统一格式命名,按统一格式调用
					node /^web\d+\.fang\.com/ {
						... puppet code ...
					}

			主机命名规范:
				角色-运营商-机房名-IP.DOMAIN.TLD
					web-unicom-jxq-1.1.1.1.fang.com

				node basenode {
					include ntp
				}

				node web.fang.com inherits basenode {
					include nginx::proxy
				}

			对节点配置分段管理:
				/etc/puppet/mainfests/
					site.pp
						import "webservers/*.pp"

					webservers/
						unicom.pp
						telecom.pp
					cacheservers/
					appservers/

	面临的两个问题:
		1.主机名解析
		2.如何为系统准备好puppet agent

	puppet的多环境支持:
		master环境配置段
			[master]
				environment = production,testing,development
			[production]
			manifest = /etc/puppet/environment/production/manifests/site.pp
			modulepath = /etc/puppet/environment/production/modules/
			fileserverconfig = /etc/puppet/fileserver.conf

			[testing]
			manifest = /etc/puppet/environment/testing/manifests/site.pp
			modulepath = /etc/puppet/environment/testing/modules/
			fileserverconfig = /etc/puppet/fileserver.conf

			[development]
			manifest = /etc/puppet/environment/development/manifests/site.pp
			modulepath = /etc/puppet/environment/development/modules/
			fileserverconfig = /etc/puppet/fileserver.conf

		agent配置文件:
			[agent]
			environment = testing

puppet的文件服务器:
	fileserver.conf
		生效的结果是结合puppet.conf和auth.conf,用于实现安全配置,例如agent能够或不能访问master端的哪些文件

	[mount_point]
	path /PATH/TO/SOMEWHERE
	allow HOSTNAME
	allow_ip IP
	deny all

auth.conf配置文件
	认证配置文件,为puppet提供acl功能,主要应用于puppet的Restful API的调用

	path /path_to_somewhere
	auth yes
	method find,save
	allow
	allow_ip

namespaceauth.conf
	用于控制名称空间的访问法则
	[puppetrun]
	allow node2.fang.com

	名称空间:
		fileserver,puppetmaster,puppetrunners,puppetreports,resource

autosign.conf:
	让master在接收到agent的证书签署后直接自动为其签署
		*.fang.com

puppet kick模式:
	3.8版本后被废弃

puppet的dashboard


puppet master的扩展
	单机扩展:
		Nginx + Mongrel
		Nginx + Passenger
		httpd + Passenger