在Puppet中,编码样式定义了在尝试将机器配置上的基础结构转换为代码时需要遵循的所有标准. Puppet使用资源工作并执行其所有已定义的任务.
Puppet的语言定义有助于以结构化方式指定所有资源,这是管理需要管理的任何目标计算机所必需的. Puppet使用Ruby作为其编码语言,它具有多个内置功能,可以通过代码端的简单配置轻松完成任务.
基本单位
Puppet使用多种基本编码样式,易于理解和管理.以下是少数列表.
资源
在Puppet中,资源称为基本建模单元,用于管理或修改任何目标系统.资源涵盖系统的所有方面,例如文件,服务和包. Puppet具有内置功能,允许用户或开发人员开发自定义资源,这有助于管理机器的任何特定单元
在Puppet中,所有资源都聚合在一起通过使用"define"或"类".这些聚合功能有助于组织模块.以下是一个示例资源,它由多个类型,标题和属性列表组成,Puppet可以使用这些属性支持多个属性. Puppet中的每个资源都有自己的默认值,可以在需要时覆盖它.
文件的样本木偶资源
在以下命令中,我们正在尝试为特定文件指定权限.
file { '/etc/passwd': owner => superuser, group => superuser, mode => 644, }
每当在任何机器上执行上述命令时,它将验证系统中的passwd文件是否按照描述配置.之前的文件:冒号是资源的标题,可以在Puppet配置的其他部分中称为资源.
除了标题之外指定本地名称
file { 'sshdconfig': name => $operaSystem ? { solaris => '/usr/local/etc/ssh/sshd_config', default => '/etc/ssh/sshd_config', }, owner => superuser, group => superuser, mode => 644, }
通过使用始终相同的标题,可以很容易地在配置中引用文件资源而无需重复OS相关逻辑.
另一个例子可能是使用依赖于文件的服务.
service { 'sshd': subscribe => File[sshdconfig], }
使用此依赖关系后, sshd 服务将始终重启 sshdconfig 文件更改.这里要记住的一点是文件[sshdconfig] 是一个声明为文件,小写但如果我们将其更改为 FILE [sshdconfig] 那么它本来就是参考.
在声明资源时需要记住的一个基本点是,每个配置文件只能声明一次.多次重复声明同一资源将导致错误.通过这个基本概念,Puppet确保配置得到很好的建模.
我们甚至有能力管理资源依赖,这有助于管理多种关系.
service { 'sshd': require => File['sshdconfig', 'sshconfig', 'authorized_keys']}
元参数
元参数在Puppet中被称为全局参数.元参数的一个关键特性是,它适用于Puppet中的任何类型的资源.
资源默认
当需要定义默认值时资源属性值,Puppet提供了一组语法来归档它,使用没有标题的大写资源规范.
例如,如果我们想要设置所有可执行文件的默认路径它可以使用以下命令完成.
Exec { path => '/usr/bin:/bin:/usr/sbin:/sbin' } exec { 'echo Testing mataparamaters.': }
在上面的命令中,第一个语句Exec将为exec资源设置默认值. Exec资源需要一个完全限定的路径或看起来像可执行文件的路径.有了这个,就可以为整个配置定义一个默认路径.默认值适用于Puppet中的任何资源类型.
默认值不是全局值,但是,它们仅影响它们的定义范围或下一个变量.如果想要为完整配置定义默认,那么我们在下一节中定义默认和类.
资源集合
聚合是一种收集事物的方法. Puppet支持非常强大的聚合概念.在Puppet中,聚合用于将资源分组,这是Puppet的基本单元. Puppet中的聚合概念是通过使用两种强大的方法实现的,这两种方法称为类和定义.
类和定义
类负责对节点的基本方面进行建模.他们可以说node是一个Web服务器,这个特定的节点就是其中之一.在Puppet中,编程类是单例,每个节点可以评估一次.
另一方面,定义可以在单个节点上多次使用.它们的工作方式类似,因为使用该语言创建了自己的Puppet类型.它们被创建为每次使用不同的输入多次.这意味着可以将变量值传递给定义.
类和定义之间的差异
类和定义之间唯一的关键区别在于定义在构建结构和分配资源时,每个节点只对类进行一次评估,另一方面,在同一个节点上多次使用定义.
类
使用class关键字引入Puppet中的类,并将该特定类的内容包装在花括号内,如下例所示.
class unix { file { '/etc/passwd': owner => 'superuser', group => 'superuser', mode => 644; '/etc/shadow': owner => 'vipin', group => 'vipin', mode => 440; } }
在下面的例子中,我们使用了一些类似于上面的简写.
class unix { file { '/etc/passwd': owner => 'superuser', group => 'superuser', mode => 644; } file {'/etc/shadow': owner => 'vipin', group => 'vipin', mode => 440; } }
Puppet类中的继承
在Puppet中,OOP概念默认情况下支持继承,其中类可以扩展先前的功能,而无需在新创建的类中再次复制和粘贴完整的代码位.继承允许子类覆盖父类中定义的资源设置.使用继承时要记住的一个关键是,类只能从一个父类继承功能,不能超过一个.
class superclass inherits testsubclass { File['/etc/passwd'] { group => wheel } File['/etc/shadow'] { group => wheel } }
如果需要撤消父类中指定的某些逻辑,我们可以使用 undef命令.
class superclass inherits testsubcalss { File['/etc/passwd'] { group => undef } }
使用继承的替代方法
class tomcat { service { 'tomcat': require => Package['httpd'] } } class open-ssl inherits tomcat { Service[tomcat] { require +> File['tomcat.pem'] } }
Puppet中的嵌套类
Puppet支持类的嵌套的概念,它允许使用嵌套类,这意味着一个类在另一个类中.这有助于实现模块化和范围界定.
class testclass { class nested { file { '/etc/passwd': owner => 'superuser', group => 'superuser', mode => 644; } } } class anotherclass { include myclass::nested }
参数化类
在Puppet中,类可以扩展其功能以允许将参数传递到类中.
传递参数在一个类中,可以使用以下构造 :
class tomcat($version) { ... class contents ... }
在Puppet中要记住的一个关键点是,使用include函数不会添加带参数的类,而是生成的类可以作为定义添加.
node webserver { class { tomcat: version => "1.2.12" } }
默认值作为类中的参数
class tomcat($version = "1.2.12",$home = "/var/www") { ... class contents ... }
运行阶段
Puppet支持运行阶段的概念,这意味着用户可以根据需要添加多个阶段以管理任何特定资源或多个资源.当用户想要开发复杂的目录时,此功能非常有用.在复杂的目录中,需要编译大量资源,同时要记住所定义的资源之间的依赖关系不应受到影响.
Run Stage在管理方面非常有用资源依赖.这可以通过在定义的阶段中添加类来完成,其中特定的类包含资源的集合.在运行阶段,Puppet保证每次目录运行时定义的阶段将以指定的可预测顺序运行并在任何Puppet节点上应用.
为了使用它,需要声明除已经存在的阶段之外的其他阶段,然后可以将Puppet配置为在require " - >"和"+>之前使用相同的资源关系语法以指定的顺序管理每个阶段. "的.然后,该关系将保证与每个阶段关联的类的顺序.
使用Puppet声明性语法声明其他阶段
stage {"first":before => Stage [main]} stage {"last":require => Stage [main]}
一旦声明了阶段,一个类可能会与舞台以外的舞台相关联.
class { "apt-keys": stage => first; "sendmail": stage => main; "apache": stage => last; }
与apt-key类相关的所有资源都将首先运行. Sendmail中的所有资源都是主类,与Apache相关的资源将是最后一个阶段.
定义
在Puppet中,收集任何清单文件中的资源都是通过类或定义完成的.定义与Puppet中的类非常相似,但它们是用 define关键字(非类)引入的,它们支持参数而不是继承.它们可以使用不同的参数在同一系统上多次运行.
例如,如果想要创建一个控制源代码存储库的定义,其中一个人试图在其上创建多个存储库相同的系统,然后可以使用定义而不是类.
define perforce_repo($path) { exec { "/usr/bin/svnadmin create $path/$title": unless => "/bin/test -d $path", } } svn_repo { puppet_repo: path => '/var/svn_puppet' } svn_repo { other_repo: path => '/var/svn_other' }
这里要注意的关键点是变量如何与定义一起使用.我们使用( $ )美元符号变量.在上面,我们使用了$ title.定义可以同时具有$ title和$ name,可以用它来表示名称和标题.默认情况下,$ title和$ name设置为相同的值,但可以设置title属性并将不同的名称作为参数传递. $ title和$ name仅适用于定义,不适用于类或其他资源.
模块
模块可以定义为所有模块的集合Puppet master用于在任何特定Puppet节点(代理)上应用配置更改的配置.它们也被称为执行特定任务所需的不同类型配置的便携式集合.例如,一个模块可能包含配置Postfix和Apache所需的所有资源.
节点
节点是非常简单的剩余步骤,这就是我们如何匹配我们定义的内容("这就是网络服务器的样子"),选择哪些机器来完成这些指令.
节点定义看起来很像类,包括支持继承,但是特殊的,当节点(运行puppet客户端的托管计算机)连接到Puppet主守护程序时,其名称将在定义的节点列表中查找.定义的信息将针对节点进行评估,然后节点将发送该配置.
节点名称可以是短主机名或完全限定的域名(FQDN).
node'www.vipin.com'{包括普通的包括apache,squid }
上面的定义创建了一个名为www.vipin.com的节点,包括常见的Apache和Squid classe
我们可以发送通过用逗号分隔每个节点的相同配置.
node 'www.vipin.com' { include common include apache, squid }
匹配节点的正则表达式
node /^www\d+$/ { include testing }
节点继承
节点支持有限的继承tance模型.与类一样,节点只能从另一个节点继承.
node 'www.testing2.com' inherits 'www.testing.com' { include loadbalancer }
在上面的代码中,www.testing2.com继承了www.testing.com的所有功能.另外还有一个负载均衡器类.
高级支持的功能
报价 : 在大多数情况下,我们不需要在Puppet中引用字符串.任何以字母开头的字母数字字符串都将保留而不引用.但是,为任何非负值引用字符串始终是最佳做法.
带引号的可变插值
到目前为止,我们已经提到过变量在定义方面.如果需要将这些变量与字符串一起使用,请使用双引号,而不是单引号.单引号字符串不会做任何变量插值,双引号字符串会做.变量可以放在 {} 中,这样可以更容易一起使用,更容易理解.
$ value ="$ {one} $ {two}"
作为最佳实践,应该对所有不需要字符串插值的字符串使用单引号.
大写
大写是一个用于引用,继承和设置特定资源的默认属性的过程.基本上有两种使用它的方法.
参考 : 它是引用已创建资源的方式.它主要用于依赖目的,必须大写资源的名称.例如,require => file [sshdconfig]
继承 : 从子类重写父类的设置时,请使用资源名称的大写版本.使用小写版本将导致错误.
设置默认属性值 : 使用没有标题的大写资源可以设置资源的默认值.
数组
Puppet允许在多个区域中使用数组[一,二,三].
多个类型成员(例如主机定义中的别名)接受其值中的数组.具有多个别名的主机资源看起来如下所示.
host { 'one.vipin.com': alias => [ 'satu', 'dua', 'tiga' ], ip => '192.168.100.1', ensure => present, }
以上代码会将主机'one.brcletest.com'添加到主机列表中有三个别名'satu''dua''tiga'.如果想要为一个资源添加多个资源,可以按照以下示例所示完成.
resource { 'baz': require => [ Package['rpm'], File['testfile'] ], }
变量
Puppet支持多种变量,就像大多数其他编程语言一样. Puppet变量用 $ 表示.
$content = 'some content\n' file { '/tmp/testing': content => $content }
如前所述,Puppet是一种声明性语言,这意味着它的范围和赋值规则与命令式语言不同.主要区别在于,无法在单个范围内更改变量,因为它们依赖于文件中的顺序来确定变量的值.顺序与声明性语言无关.
$user = root file { '/etc/passwd': owner => $user, } $user = bin file { '/bin': owner => $user, recurse => true, }
变量范围
变量范围定义所有定义的变量是否有效.与最新功能一样,Puppet目前是动态范围的,在Puppet术语中意味着定义的所有变量都在其范围而不是它们定义的位置进行评估.
$test = 'top' class Testclass { exec { "/bin/echo $test": logoutput => true } } class Secondtestclass { $test = 'other' include myclass } include Secondtestclass
合格变量
Puppet支持在类或定义中使用限定变量.当用户希望在其他类中使用相同的变量时,这非常有用,他已定义或将要定义.
class testclass { $ test ='content'} class secondtestclass { $ other = $ myclass :: test }
在上面的代码中,$ other变量的值评估内容.
条件
条件是当用户希望在满足定义的条件或所需条件时执行一组语句或代码时的情况. Puppet支持两种类型的条件.
选择器条件,只能在定义的资源中使用以选择正确的机器值.
语句条件是清单中更广泛使用的条件,其有助于包括用户希望包括在相同清单文件中的附加类.在类中定义一组不同的资源,或做出其他结构决策.
选择器
当用户希望指定资源时,选择器很有用属性和变量与基于事实或其他变量的默认值不同.在Puppet中,选择器索引的工作方式类似于多值三向运算符.选择器还能够在没有值的情况下定义自定义默认值,这些值在清单中定义并与条件匹配.
$owner = $Sysoperenv ? { sunos => 'adm', redhat => 'bin', default => undef, }
在Puppet 0.25.0的更高版本中,选择器可用作正则表达式.
$owner = $Sysoperenv ? { /(Linux|Ubuntu)/ => 'bin', default => undef, }
在上面的例子中,选择器 $ Sysoperenv 值匹配Linux或Ubuntu,然后bin将是选定的结果,否则用户将被设置为undefined.
语句条件
语句条件是Puppet中的其他类型的条件语句这与Shell脚本中的switch case条件非常相似.在此,定义了多组case语句,并且给定的输入值与每个条件匹配.
执行与给定输入条件匹配的case语句.此case语句条件没有任何返回值.在Puppet中,条件语句的一个非常常见的用例是基于底层操作系统运行一组代码位.
case $ Sysoperenv { sunos: { include solaris } redhat: { include redhat } default: { include generic} }
Case语句还可以通过用逗号分隔它们来指定多个条件.
case $Sysoperenv { development,testing: { include development } testing,production: { include production } default: { include generic } }
If-Else Statement
Puppet支持基于条件的操作的概念.为了实现它,If/else语句根据条件的返回值提供分支选项.如下例所示 :
if $ Filename { file {'/some/file':ensure => $} file {'/some/other/file':ensure => }
最新版本的Puppet支持变量表达式,其中if语句也可以根据表达式的值进行分支./p>
if $ machine =='production'{ include ssl } else { include nginx }
为了在代码中实现更多样化并执行复杂的条件操作,Puppet支持嵌套的if/else语句,如下面的代码所示./p>
if $Filename { file { '/some/file': ensure => present } } else { file { '/some/other/file': ensure => present } }
虚拟资源
虚拟资源是那些未发送到客户端的虚拟资源,除非已实现.
以下是在Puppet中使用虚拟资源的语法.
@user {vipin:ens ure =>
在上面的例子中,用户vipin被虚拟定义,以实现可以在集合中使用的定义.
User< | title == vipin |>
评论
在任何代码位中使用注释来创建关于一组代码行的附加节点它的功能.在Puppet中,目前有两种类型的支持注释.
Unix shell样式注释.他们可以在自己的行或下一行.
多行c风格的评论.
以下是shell样式评论的示例.
#这是评论
以下是多行注释的示例.
/* 这是一条评论 */
运算符优先级
Puppet运算符优先级符合大多数系统中的标准优先级,从最高到最低.
以下是表达式列表
! =不
/=次数和分数
- + =减号,加上
<< >> =左移和右移
==!= =不等于,等于
> =< => < =大于等于,小于或等于,大于,小于
比较表达式
比较表达式用于用户想要在满足给定条件时执行一组语句.比较表达式包括使用==表达式进行相等性测试.
if $environment == 'development' { include openssl } else { include ssl }
不等于示例
if $ environment!='development'{ $ otherenvironment ='testing'} else { $ otherenvironment ='production'}
算术表达式
$ one = 1 $ one_thirty = 1.30 $ two = 2.034e-2 $ result =((($ two + 2)/$ one_thirty)+ 4 * 5.45) - (6<<($ 2 + 4) )+(0× 800 + -9)
布尔表达式
布尔表达式可以使用或,和, &.
$ one = 1 $ two = 2 $ var =($ one< $ two)和($ one + 1 == $ 2)
正则表达式
Puppet支持使用=〜进行正则表达式匹配(匹配)和!〜(不匹配).
if $ website =〜/^www(\\\+)〜\\./{ notice('Welcome web server#$ 1')}
像case和selector正则表达式匹配为每个创建有限的范围变量正则表达式.
exec { "Test": command => "/bin/echo now we don’t have openssl installed on machine > /tmp/test.txt", unless => "/bin/which php" }
同样,我们可以使用除非,除非始终执行命令,除非命令在除非之外退出成功.
exec { "Test": command => "/bin/echo now we don’t have openssl installed on machine > /tmp/test.txt", unless => "/bin/which php" }
使用模板
模板用于需要时有一个预定义的结构,将在Puppet中的多个模块中使用,这些模块将分布在多台机器上.使用模板的第一步是创建一个使用模板方法呈现模板内容的步骤.
file { "/etc/tomcat/sites-available/default.conf": ensure => "present", content => template("tomcat/vhost.erb") }
Puppet在处理本地文件时做了一些假设,以强制执行组织和模块化. Puppet在模块目录中的文件夹apache/templates中查找vhost.erb模板.
定义和触发服务
在Puppet中,它有一种称为服务的资源,它能够管理在任何特定计算机或环境上运行的所有服务的生命周期.服务资源用于确保初始化和启用服务.它们也用于服务重启.
例如,在我们设置apache虚拟主机的tomcat的前一个模板中.如果想要确保在虚拟主机更改后重新启动apache,我们需要使用以下命令为apache服务创建服务资源.
service { 'tomcat': ensure => running, enable => true }
定义资源时,我们需要包含notify选项以触发重启.
file { "/etc/tomcat/sites-available/default.conf": ensure => "present", content => template("vhost.erb"), notify => Service['tomcat'] }