📅  最后修改于: 2020-10-31 14:04:50             🧑  作者: Mango
在Puppet中,编码风格定义了在尝试将计算机配置上的基础结构转换为代码时需要遵循的所有标准。木偶使用资源工作并执行其所有已定义的任务。
Puppet的语言定义有助于以结构化的方式指定所有资源,这是管理需要管理的任何目标计算机所必需的。 Puppet使用Ruby作为其编码语言,它具有多种内置功能,通过在代码侧进行简单的配置就可以很轻松地完成工作。
Puppet使用多种易于理解和管理的基本编码样式。以下是一些清单。
在Puppet中,资源被称为基本建模单元,用于管理或修改任何目标系统。资源涵盖了系统的所有方面,例如文件,服务和程序包。 Puppet具有内置功能,该功能允许用户或开发人员开发自定义资源,从而有助于管理机器的任何特定单元
在Puppet中,通过使用“ define”或“ classs”将所有资源聚合在一起。这些聚合功能有助于组织模块。以下是一个示例资源,该资源由多种类型,一个标题和一系列属性组成,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],
}
在这种依赖性下,一旦sshdconfig文件更改, sshd服务将始终重新启动。这里要记住的一点是File [sshdconfig]是作为File的声明(小写),但是如果我们将其更改为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中的聚合概念是通过使用两种称为类和定义的强大方法来实现的。
类负责对节点的基本方面进行建模。他们可以说节点是Web服务器,而这个特定节点就是其中之一。在Puppet中,编程类是单例的,并且每个节点可以对它们进行一次评估。
另一方面,定义可以在单个节点上多次使用。它们的工作方式与使用该语言创建自己的Puppet类型类似。它们被创建为可多次使用,且每次具有不同的输入。这意味着可以将变量值传递到定义中。
类和定义之间的唯一关键区别是,在定义建筑结构和分配资源时,每个节点仅对类进行一次评估,而另一方面,在同一单个节点上多次使用定义。
Puppet中的类是使用class关键字引入的,并且该特定类的内容包装在花括号内,如以下示例所示。
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中,默认情况下支持继承的OOP概念,其中类可以扩展以前的功能,而无需在新创建的类中再次复制和粘贴完整的代码位。继承允许子类覆盖父类中定义的资源设置。使用继承时要记住的一件事是,一个类只能从一个父类(最多一个)继承特性。
class superclass inherits testsubclass {
File['/etc/passwd'] { group => wheel }
File['/etc/shadow'] { group => wheel }
}
如果需要撤消在父类中指定的某些逻辑,则可以使用undef command 。
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支持类嵌套的概念,在该概念中,它允许使用嵌套类,这意味着一个类在另一个类之内。这有助于实现模块化和范围界定。
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支持运行阶段的概念,这意味着用户可以根据需要添加多个阶段,以管理任何特定资源或多个资源。当用户想要开发复杂的目录时,此功能非常有用。在一个复杂的目录中,有很多资源需要编译,同时要记住,所定义的资源之间的依赖性不应该受到影响。
运行阶段对于管理资源依赖关系非常有帮助。这可以通过在定义的阶段添加类来完成,其中特定的类包含资源的集合。通过运行阶段,Puppet保证每次目录运行并应用于任何Puppet节点时,定义的阶段都将以指定的可预测顺序运行。
为了使用此功能,需要声明已经存在的阶段之外的其他阶段,然后可以将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关键字(不是class)引入的,并且它们支持参数而不是继承。它们可以使用不同的参数在同一系统上多次运行。
例如,如果要创建一个定义来控制源代码存储库的定义,而在其中试图在同一系统上创建多个存储库,则可以使用该定义而不是类。
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属性并传递不同的name作为参数。 $ title和$ name仅在定义中起作用,而在类或其他资源中不起作用。
可以将模块定义为所有配置的集合,Puppet主设备将使用该模块在任何特定Puppet节点(代理)上应用配置更改。它们也被称为不同类型的配置的便携式集合,它们是执行特定任务所必需的。例如,一个模块可能包含配置Postfix和Apache所需的所有资源。
节点是非常简单的剩余步骤,这就是我们如何将定义的内容(“这就是Web服务器的外观”)与选择要执行这些指令的机器相匹配的方式。
节点定义看起来完全类似于类,包括支持的继承,但是它们很特殊,当节点(运行p客户端的受管计算机)连接到Puppet主守护程序时,其名称将在已定义的节点列表中查找。将为节点评估定义的信息,然后节点将发送该配置。
节点名称可以是简短的主机名或完全限定的域名(FQDN)。
node 'www.vipin.com' {
include common
include apache, squid
}
上面的定义创建了一个名为www.vipin.com的节点,并包括通用类,Apache和Squid类
我们可以通过用逗号分隔每个节点来将相同的配置发送到不同的节点。
node 'www.testing.com', 'www.testing2.com', 'www3.testing.com' {
include testing
include tomcat, squid
}
node /^www\d+$/ {
include testing
}
节点支持有限的继承模型。像类一样,节点只能从另一个节点继承。
node 'www.testing2.com' inherits 'www.testing.com' {
include loadbalancer
}
在上面的代码中,www.testing2.com除了附加的loadbalancer类之外,还继承了www.testing.com的所有功能。
引用-在大多数情况下,我们不需要在Puppet中引用字符串。任何以字母开头的字母数字字符串都应不加引号。但是,始终最好的做法是为任何非负值引用字符串。
到目前为止,我们已经在定义方面提到了变量。如果需要将这些变量与字符串使用,请使用双引号而不是单引号。单引号字符串不会执行任何变量插值,双引号字符串则可以。变量可以放在{}中,这使得它们更易于一起使用和理解。
$value = "${one}${two}"
最佳做法是,对不需要字符串插值的所有字符串都应使用单引号。
大写是一个过程,用于引用,继承和设置特定资源的默认属性。基本上有两种使用它的基本方法。
引用-这是引用已经创建的资源的方式。它主要用于依赖关系,必须将资源名称大写。例如,require =>文件[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支持多个变量。人偶变量用$表示。
$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中,选择器索引的工作方式类似于多值三向运算符。选择器还能够以无值定义自定义默认值,这些值在清单中定义并与条件匹配。
$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 Statement还可以通过用逗号分隔多个条件来指定它们。
case $Sysoperenv {
development,testing: { include development } testing,production: { include production }
default: { include generic }
}
Puppet支持基于条件的操作的概念。为了实现它,If / else语句根据条件的返回值提供分支选项。如以下示例所示-
if $Filename {
file { '/some/file': ensure => present }
} else {
file { '/some/other/file': ensure => present }
}
Puppet的最新版本支持变量表达式,其中if语句也可以基于表达式的值进行分支。
if $machine == 'production' {
include ssl
} else {
include nginx
}
为了在代码中实现更多多样性并执行复杂的条件操作,Puppet支持嵌套的if / else语句,如以下代码所示。
if $ machine == 'production' {
include ssl
} elsif $ machine == 'testing' {
include nginx
} else {
include openssl
}
虚拟资源是那些除非实现就不会发送给客户端的资源。
以下是在Puppet中使用虚拟资源的语法。
@user { vipin: ensure => present }
在上面的示例中,虚拟定义了用户vipin以实现一个人可以在集合中使用的定义。
User
在任何代码位中都使用注释,以形成关于一组代码行及其功能的附加节点。在Puppet中,当前有两种支持的注释。
以下是外壳样式注释的示例。
# this is a comment
以下是多行注释的示例。
/*
This is a comment
*/
从最高到最低,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 << ($two + 4)) + (0×800 + -9)
布尔表达式可以使用or,and,&not。
$one = 1
$two = 2
$var = ( $one < $two ) and ( $one + 1 == $two )
Puppet支持使用=〜(匹配)和!〜(不匹配)进行正则表达式匹配。
if $website =~ /^www(\d+)\./ {
notice('Welcome web server #$1')
}
像大小写和选择器正则表达式匹配一样,为每个正则表达式创建有限范围的变量。
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在modules目录下的apache / templates文件夹中寻找vhost.erb模板。
在Puppet中,它具有称为服务的资源,该资源能够管理在任何特定机器或环境上运行的所有服务的生命周期。服务资源用于确保服务已初始化并启用。它们还用于服务重启。
例如,在先前的tomcat模板中,我们在其中设置了apache虚拟主机。如果要确保在更改虚拟主机后重新启动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']
}