Introduction
简而言之,服务器配置管理(通常也称为IT自动化)是一种将基础设施管理转化为代码库的解决方案,它描述了在一组可以进行版本控制并易于重用的配置脚本中部署服务器所需的所有流程。随着时间的推移,它可以大大提高任何服务器基础设施的完整性。
在以前的guide](https://andsky.com/tech/tutorials/an-introduction-to-configuration-management),中,我们谈到了为您的服务器基础设施实施配置管理策略的主要好处、配置管理工具如何工作,以及这些工具通常有哪些共同之处。
本系列的这一部分将引导您完成使用Pupet自动配置服务器的过程,Pupet是一种流行的配置管理工具,能够以透明的方式管理复杂的基础设施,使用主服务器来协调节点的配置。我们将重点介绍创建一个简化示例以使用Apache完全自动化部署Ubuntu 18.04Web服务器所需的语言术语、语法和功能。
为了实现我们的目标,以下是我们需要自动执行的步骤:
1.更新apt
缓存
2.安装阿帕奇
3.创建自定义文档根目录
4.在自定义文档根目录中放置一个index.html
文件
5.应用模板来设置我们的自定义虚拟主机
6.重启阿帕奇
我们将首先看一看Pupet使用的术语,然后概述可用于编写清单的主要语言功能。在本指南的最后,我们将分享完整的示例,以便您可以亲自尝试。
<$>[备注] 注意: 本指南旨在向您介绍傀儡语言以及如何编写清单以自动执行服务器配置。有关木偶的更具介绍性的视图,包括安装和开始使用此工具所需的步骤,请参阅木偶的官方documentation. <$>
入门
在我们开始更实际地了解Puppet之前,重要的是我们要熟悉这个工具引入的重要术语和概念。
傀儡术语
- 傀儡Master :控制节点配置的主服务器
- 木偶代理节点 :木偶主人控制的节点
- 清单 :包含一组要执行的指令的文件
- 资源 :声明系统元素及其状态应如何更改的代码部分。例如,要安装一个包,我们需要定义a_Package_resource,并确保将其状态设置为
已安装
- 模块 :以预定义的方式组织的清单和其他相关文件的集合,以促进资源调配的部分共享和重用
- 类 :就像常规编程语言一样,在Pupket中使用类是为了更好地组织供应,并更容易重用部分代码
- 事实 :全局变量,包含有关系统的信息,如网络接口和操作系统
- 服务 :用于触发服务状态的改变,如重启或停止服务
木偶配置是使用基于Ruby的定制DSL(域特定语言)编写的。
资源
使用Pupet,任务或步骤是通过声明资源 来定义的。资源可以表示包、文件、服务、用户和命令。它们可能有一个状态,如果声明的资源的状态与系统上当前的状态不同,则会触发系统更改。例如,如果您的清单中的_PACKAGE_RESOURCE设置为installed
,则如果之前未安装该程序包,则会在系统上触发该程序包的安装。
A_Package_resource如下所示:
1package { 'nginx':
2 ensure => 'installed'
3}
你可以通过声明一个exec
资源来执行任意命令,如下所示:
1exec { 'apt-get update':
2 command => '/usr/bin/apt-get update'
3}
请注意,第一行的apt-get update
部分不是实际的命令声明,而是这个唯一资源的标识符。我们经常需要从资源中引用其他资源,为此我们使用它们的标识符。在这种情况下,标识符是apt-get update
,但它可以是任何其他字符串。
资源依赖
在编写清单时,重要的是要记住,Puppet不会按照定义的顺序计算资源。这是那些开始使用Puppet的人常见的困惑来源。资源必须明确定义彼此之间的依赖关系,否则无法保证哪个资源将首先被评估并执行。
举个简单的例子,假设您想要执行一个命令,但您需要确保首先安装了一个依赖项:
1package { 'python-software-properties':
2 ensure => 'installed'
3}
4
5exec { 'add-repository':
6 command => '/usr/bin/add-apt-repository ppa:ondrej/php5 -y'
7 require => Package['python-software-properties']
8}
选项将对另一个资源的引用作为参数接收。在本例中,我们指的是标识为python-soft-Properties
的_Package_resource。
需要注意的是,虽然我们使用exec
、Package
等来声明资源(小写),但当引用先前定义的资源时,我们使用Exec
、Package
,依此类推(大写)。
现在假设您需要确保一项任务在另一项任务 之前执行。对于这种情况,我们可以使用bepre
选项:
1package { 'curl':
2 ensure => 'installed'
3 before => Exec['install script']
4}
5
6exec { 'install script':
7 command => '/usr/bin/curl http://example.com/some-script.sh'
清单格式
清单基本上是资源声明的集合,使用扩展名.pp
。下面是一个简单的剧本示例,它执行两个任务:更新apt
缓存,然后安装vim
:
1exec { 'apt-get update':
2 command => '/usr/bin/apt-get update'
3}
4
5package { 'vim':
6 ensure => 'installed'
7 require => Exec['apt-get update']
8}
在本指南结束之前,我们将看到一个更真实的清单示例,详细说明。下一节将概述可用于编写PupPot清单的最重要的元素和功能。
编写清单
使用变量
变量可以在清单中的任何位置定义。最常见的变量类型是字符串和字符串数组,但也支持其他类型,如布尔值和散列。
下面的示例定义了稍后在资源中使用的字符串变量:
1$package = "vim"
2
3package { $package:
4 ensure => "installed"
5}
使用循环
循环通常用于使用不同的输入值重复执行任务。例如,您可以创建一个任务,然后使用一个循环来对您要安装的所有不同的包重复执行该任务,而不是创建10个任务来安装10个不同的包。
在Puptet中使用不同值重复任务的最简单方法是使用数组,如下例所示:
1$packages = ['vim', 'git', 'curl']
2
3package { $packages:
4 ensure => "installed"
5}
从版本4开始,Pupket支持迭代任务的其他方法。下面的示例与前面的示例执行相同的操作,但这次使用的是each
迭代器。此选项使您可以更灵活地遍历资源定义:
1$packages.each |String $package| {
2 package { $package:
3 ensure => "installed"
4 }
5}
使用条件句
条件可以用于动态地决定是否应该执行代码块,例如,基于变量或命令的输出。
Pupket支持传统编程语言中的大多数条件结构,如if/Else‘和
Case语句。此外,
exec`等资源将支持像条件一样工作的属性,但只接受命令输出作为条件。
假设您想要基于a_act_执行一个命令。在这种情况下,因为您想测试变量的值,所以需要使用支持的条件结构之一,如if/ell
:
1if $osfamily != 'Debian' {
2 warning('This manifest is not supported on this OS.')
3}
4else {
5 notify { 'Good to go!': }
6}
另一种常见情况是,您希望根据另一个命令的输出来调整命令的执行。对于这种情况,您可以使用onlyif
或unless
,如下例所示。该命令只有在/bin/哪个php
的输出成功时才会执行,即该命令以0 状态退出:
1exec { "Test":
2 command => "/bin/echo PHP is installed here > /tmp/test.txt",
3 onlyif => "/bin/which php"
4}
类似地,unless
将一直执行命令,除非unless
下的命令成功退出:
1exec { "Test":
2 command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
3 unless => "/bin/which php"
4}
使用模板
模板通常用于设置配置文件,允许使用变量和其他旨在使这些文件更具通用性和可重用性的功能。Puptet支持两种不同的模板格式:Embedded Puptet(EPP)和Embedded Ruby(ERB)。但是,EPP格式仅适用于最新版本的Pupket(从4.0版开始)。
下面是一个用于设置一个Apache虚拟主机的ERB模板的示例,该模板使用一个变量来设置该主机的文档根目录:
1<VirtualHost *:80>
2 ServerAdmin webmaster@localhost
3 DocumentRoot <%= @doc_root %>
4
5 <Directory <%= @doc_root %>>
6 AllowOverride All
7 Require all granted
8 </Directory>
9</VirtualHost>
为了应用模板,我们需要创建一个file
资源,该资源使用template
方法呈现模板内容。您可以通过以下方式应用此模板来替换默认的Apache虚拟主机:
1file { "/etc/apache2/sites-available/000-default.conf":
2 ensure => "present",
3 content => template("apache/vhost.erb")
4}
在处理本地文件时,为了加强组织性和模块化,Puptet做了一些假设。在这种情况下,Puptet将在您的模块目录内的apache/temples
文件夹中查找一个vhost.erb
模板文件。
定义和触发服务
服务资源用于确保服务已初始化并启用。它们还用于触发服务重启。
让我们考虑一下前面的模板使用示例,在该示例中,我们设置了一个Apache虚拟主机。如果您希望确保在虚拟主机更改后重新启动Apache,您首先需要为Apache服务创建一个_SERVICE_RESOURCE。这是在Pupppt中定义此类资源的方式:
1service { 'apache2':
2 ensure => running,
3 enable => true
4}
现在,在定义资源时,需要包含notfy
选项才能触发重启:
1file { "/etc/apache2/sites-available/000-default.conf":
2 ensure => "present",
3 content => template("vhost.erb"),
4 notify => Service['apache2']
5}
清单示例
现在让我们来看看一个清单,它将自动在Ubuntu 14.04系统中安装一个ApacheWeb服务器,正如本指南的介绍中所讨论的那样。
完整的示例可以在Github.]上找到,其中包括用于设置apache的模板文件和由Web服务器提供的Html文件该文件夹还包含一个流浪者文件,该文件允许您使用由流浪者.)管理的虚拟机在简化的设置中测试清单
下面你可以找到完整的舱单:
1[label default.pp]
2$doc_root = "/var/www/example"
3
4exec { 'apt-get update':
5 command => '/usr/bin/apt-get update'
6}
7
8package { 'apache2':
9 ensure => "installed",
10 require => Exec['apt-get update']
11}
12
13file { $doc_root:
14 ensure => "directory",
15 owner => "www-data",
16 group => "www-data",
17 mode => 644
18}
19
20file { "$doc_root/index.html":
21 ensure => "present",
22 source => "puppet:///modules/main/index.html",
23 require => File[$doc_root]
24}
25
26file { "/etc/apache2/sites-available/000-default.conf":
27 ensure => "present",
28 content => template("main/vhost.erb"),
29 notify => Service['apache2'],
30 require => Package['apache2']
31}
32
33service { 'apache2':
34 ensure => running,
35 enable => true
36}
货单说明
第一行
清单以变量定义$doc_root
开始。此变量稍后将在资源声明中使用。
3-5行
此exec 资源执行apt-get update
命令。
第7-10行
此程序包 资源安装apache2
程序包,定义apt-get update
资源为必填项,即只有在评估了所需资源后才会执行。
第12-17行
我们在这里使用文件 资源来创建一个新目录,该目录将用作我们的文档根目录。file
资源可以用来创建目录和文件,也可以用来申请模板和将本地文件复制到远程服务器。这项任务可以在部署的任何时间点执行,所以我们不需要在这里设置任何Require
。
第19-23行
这里我们使用另一个文件 资源,这次是将本地的** index.html** 文件复制到服务器内的文档根目录。我们使用Source
参数让Pupppet知道在哪里可以找到原始文件。此命名法基于Puptet处理本地文件的方式;如果您查看Github Example repository,,您将看到应该如何创建目录结构,以便Puptet找到此资源。在执行此资源之前,需要创建文档根目录,这就是为什么我们包含一个引用前一个资源的required
选项。
第25-30行
新的文件 资源用于应用APACHE模板并通知服务重启。在本例中,我们的配置被组织在一个名为** main** 的模块中,这就是为什么模板源是** main/vhost.erb** 的原因。我们使用了一个要求
语句来确保模板资源只有在安装了apache2
包之后才会被执行,否则可能还不会出现apache使用的目录结构。
第32-35行
最后,服务 资源声明apache2
服务,我们从应用虚拟主机模板的资源通知重启该服务。
结论
PUMPET是一个强大的配置管理工具,它使用一个富有表现力的定制DSL来管理服务器资源和自动化任务。它的语言提供了高级资源,可以为您的置备设置提供额外的灵活性;重要的是要记住,资源的评估顺序与资源的定义顺序不同,因此在定义资源之间的依赖关系时需要小心,以便建立正确的执行链。
在这篇series](https://andsky.com/tech/tutorials/configuration-management-101-writing-chef-recipes),的下一篇指南中,我们将看到Chef,这是另一个强大的配置管理工具,它利用Ruby编程语言来自动化基础设施管理和配置。