配置管理101:写Puppet舱单

本指南将集中在Puppet,一个流行的配置管理工具能够以透明的方式管理复杂的基础设施,使用主服务器来编排节点的配置的功能和特性。为了给您提供工具的实践经验,我们将引导您完成创建一个简单的例子供应完全自动化使用Apache Web服务器的部署过程。

介绍

简而言之,服务器配置管理(通常称为IT自动化)是一种将基础架构管理转变为代码库的解决方案,描述了在一组可以进行版本控制和轻松重用的配置脚本中部署服务器所需的所有过程。 它可以大大提高任何服务器基础架构的完整性。

先前的指导 ,我们谈到了实施配置管理策略为您的服务器基础架构,配置管理工具是如何工作的,以及这些工具通常有什么共同之处的主要优势。

本系列的这一部分将指导您完成使用Puppet(一种流行的配置管理工具)自动化服务器配置的过程,该配置管理工具能够以透明的方式管理复杂的基础架构,使用主服务器来协调节点的配置。 我们将重点介绍创建简化示例所需的语言术语,语法和功能,以使用Apache完全自动化部署Ubuntu 14.04 Web服务器。

这是我们需要自动化以实现我们的目标的步骤列表:

  1. 更新apt缓存
  2. 安装Apache
  3. 创建自定义文档根目录
  4. 放置index.html文件中的自定义文档根目录
  5. 应用模板以设置我们的自定义虚拟主机
  6. 重新启动Apache

我们将首先看看Puppet使用的术语,然后概述可用于编写清单的主要语言特性。 在本指南的最后,我们将分享完整的示例,以便您可以自己尝试。

注意:本指南旨在向您介绍Puppet语言以及如何编写清单以自动化您的服务器设置。 对于Puppet的更多介绍视图,包括必要的安装和开始使用此工具的步骤,请查看我们如何在Ubuntu的14.04主代理设置安装Puppet 4指南。

入门

在我们可以转移到Puppet的更实际的视图之前,重要的是我们熟悉这个工具引入的重要术语和概念。

Puppet条款

  • Puppet师 :控制节点上配置的主服务器
  • Puppet代理节点 :由一个Puppet师控制的节点
  • 清单 :要执行包含一组指令的文件
  • 资源 :声明系统,以及如何其状态应该改变的元素的代码的一部分。 例如,要安装一个软件包,我们需要定义一个资源并确保其状态设置为“已安装”
  • 模块 :在一个预先定义的方式组织清单和其他相关文件的集合,以促进一个供应的共享和重用份
  • 类别 :刚刚与常规的编程语言一样,类在使用日伪更好地组织供应,使其更易于重用代码的部分
  • 事实 :包含有关系统的信息的全局变量,如网络接口和操作系统
  • 服务范围 :用于触发服务状态变化,比如重新启动或停止服务

Puppet配置是使用基于Ruby的自定义DSL(域特定语言)编写的。

资源

随着Puppet,任务或步骤通过声明的资源定义。 资源可以表示包,文件,服务,用户和命令。 它们可能具有状态,如果声明的资源的状态与当前在系统上的状态不同,则该状态将触发系统改变。 举例来说,一个资源设置为installed在你的清单将触发一个软件包安装在系统上,如果以前未安装的程序包。

这是一个程序包资源的样子:

package { 'nginx':
    ensure  => 'installed'
}

您可以通过声明的执行任意命令exec资源,如下所示:

exec { 'apt-get update':
    command => '/usr/bin/apt-get update'
}

请注意, apt-get update的第一线部分是不实际的命令声明,但这种独特的资源标识符。 通常我们需要引用资源内的其他资源,我们使用它们的标识符。 在这种情况下,所述标识符是apt-get update ,但它可以是任何其它的字符串。

资源依赖

在写清单时,重要的是要记住,Puppet不会按照它们定义的顺序来评估资源。 对于那些开始使用Puppet的人来说,这是一个常见的混乱来源。 资源必须明确地定义彼此之间的依赖关系,否则不能保证哪个资源将被评估,因此首先被执行。

作为一个简单的例子,假设你想要执行一个命令,但你需要确保依赖关系首先安装:

package { 'python-software-properties':
    ensure => 'installed'
}

exec { 'add-repository':
    command => '/usr/bin/add-apt-repository ppa:ondrej/php5 -y'
    require => Package['python-software-properties']
}

require选择接收作为参数传递给另一个资源的引用。 在这种情况下,我们指的是确定为资源 python-software-properties
重要的是要注意到,虽然我们使用的是非常重要的execpackage ,这样的宣告资源(小写),指的是先前定义的资源时,我们使用ExecPackage ,等等(大写)。

现在让我们假设你需要确保任务之前另一个执行。 对于这样的情况下,我们可以使用before选项,而不是:

package { 'curl':
    ensure => 'installed'
    before => Exec['install script']
}

exec { 'install script':
    command => '/usr/bin/curl http://example.com/some-script.sh'

清单格式

舱单基本上都是资源声明的集合,使用扩展.pp 下面你可以找到执行两个任务的简单剧本的例子:更新apt缓存并安装vim算账:

exec { 'apt-get update':
    command => '/usr/bin/apt-get update'
}

package { 'vim':
    ensure => 'installed'
    require => Exec['apt-get update']
}

在本指南结束之前,我们将看到一个更真实的清单示例,详细解释。 下一节将概述可用于编写Puppet清单的最重要的元素和功能。

写作清单

使用变量

变量可以在清单中的任何点定义。 最常见的变量类型是字符串和字符串数组,但也支持其他类型,例如布尔和散列。

下面的示例定义了稍后在资源中使用的字符串变量:

$package = "vim"

package { $package:
   ensure => "installed"
}

使用循环

循环通常用于使用不同的输入值重复任务。 例如,您可以创建单个任务,并使用循环来重复任务,以便安装所有不同的软件包,而不是创建10个任务来安装10个不同的软件包。

在Puppet中使用不同值重复任务的最简单方法是使用数组,如下面的示例所示:

$packages = ['vim', 'git', 'curl']

package { $packages:
   ensure => "installed"
}

从版本4开始,Puppet支持用于迭代任务的其他方法。 下面的例子做同样的事情与前面的例子,但使用这个时候each迭代器。 此选项为循环通过资源定义提供了更多的灵活性:

$packages.each |String $package| {
  package { $package:
    ensure => "installed"
  }
}

使用条件

例如,条件可以用于基于变量或来自命令的输出来动态地决定是否应当执行代码块。

Puppet支持大多数有条件的结构可以用传统的编程语言发现,像if/elsecase说明。 此外,有的像资源exec将支持工作就像一个条件属性,但只能接受一个命令的输出作为条件。

比方说,你要执行基于事实的命令。 在这种情况下,只要你想测试一个变量的值,你需要使用条件结构的一个支持,像if/else

if $osfamily != 'Debian' {
 warning('This manifest is not supported on this OS.')
}
else {
 notify { 'Good to go!': }
}

另一个常见的情况是,当您想根据另一个命令的输出来调节命令的执行时。 对于这样的情况下,你可以使用onlyifunless ,像下面的例子。 该命令将只执行时从输出/bin/which php是成功的,就是状态为0的命令退出:

exec { "Test":
 command => "/bin/echo PHP is installed here > /tmp/test.txt",
 onlyif => "/bin/which php"
}

同样, unless将执行命令的所有时间,除非下的命令unless成功退出:

exec { "Test":
 command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
 unless => "/bin/which php"
}

使用模板

模板通常用于设置配置文件,允许使用变量和其他旨在使这些文件更通用和可重用的功能。 Puppet支持两种不同的模板格式:嵌入式Puppet(EPP)和嵌入式Ruby(ERB)。 然而,EPP格式只适用于最新版本的Puppet(从4.0版开始)。

下面是用于设置Apache虚拟主机的ERB模板的示例,使用变量设置此主机的文档根目录:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    <Directory <%= @doc_root %>>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

为了应用模板,我们需要创建一个file呈现的模板内容与资源template的方法。 这是您将如何应用此模板来替换默认的Apache虚拟主机:

file { "/etc/apache2/sites-available/000-default.conf":
    ensure => "present",
    content => template("apache/vhost.erb") 
}    

Puppet在处理本地文件时做了一些假设,以便实施组织和模块化。 在这种情况下,Puppet会寻找一个vhost.erb中的文件夹模板文件apache/templates ,你的模块目录中。

定义和触发服务

服务资源用于确保服务被初始化和启用。 它们还用于触发服务重新启动。

让我们考虑我们以前的模板使用示例,其中我们设置一个Apache虚拟主机。 如果你想确保Apache是一个虚拟主机更改后重新启动时,您首先需要创建为Apache服务的服务资源。 这就是如何在Puppet中定义这样的资源:

service { 'apache2':
    ensure => running,
    enable => true
}

现在,定义资源的时候,你需要包括notify ,以便选择触发启动:

file { "/etc/apache2/sites-available/000-default.conf":
    ensure => "present",
    content => template("vhost.erb"),
    notify => Service['apache2'] 
} 

示例清单

现在让我们看看一个清单,它将在Ubuntu 14.04系统中自动安装Apache Web服务器,如本指南的介绍中所述。

完整的示例,包括设置Apache模板文件和一个HTML文件,由Web服务器提供服务,可以发现在Github上 该文件夹还包含一个Vagrantfile,可以让你在一个简化的安装测试清单,利用管理的虚拟机放浪

下面你可以找到完整的清单:

default.pp
$doc_root = "/var/www/example"

exec { 'apt-get update':
 command => '/usr/bin/apt-get update'
}

package { 'apache2':
 ensure  => "installed",
 require => Exec['apt-get update']
}

file { $doc_root:
 ensure => "directory",
 owner => "www-data",
 group => "www-data",
 mode => 644
}

file { "$doc_root/index.html":
   ensure => "present",
   source => "puppet:///modules/main/index.html",
   require => File[$doc_root]
}

file { "/etc/apache2/sites-available/000-default.conf":
   ensure => "present",
   content => template("main/vhost.erb"),
   notify => Service['apache2'],
   require => Package['apache2']
}

service { 'apache2':
   ensure => running,
   enable => true
}

清单解释

行1

清单开始于一个变量定义, $doc_root 此变量稍后在资源声明中使用。

行3-5

exec资源执行的apt-get update命令。

线7-10

这个资源安装包apache2 ,限定了apt-get update资源是一个要求,这意味着所需的资源进行评估后,将只被执行。

第12-17行

我们使用文件资源在这里创建一个新的目录,将作为我们的文档根目录。 file的资源可用于创建目录和文件,并且它也可用于应用模板和复制本地文件到远程服务器。 这个任务可以在配置中的任何一点执行,因此,我们没有必要设置任何require在这里。

第19-23行

我们用另一个文件的资源在这里,这个时候我们当地的index.html文件复制到服务器里面的文档根目录。 我们使用source参数,让Puppet知道在哪里找到原始文件。 这个命名是基于Puppet处理本地文件的方式; 如果你看一下在Github上的例子库中 ,你将看到如何目录结构应该是为了让Puppet找到这个资源来创建。 文档根目录需要这个资源执行前被创建,这就是为什么我们包括require参考以前的资源选择。

第25-30行

一个新的文件资源用于应用Apache模板和用于重新启动通知服务。 在这个例子中,我们的配置是一种被称为模块中组织的,这就是为什么模板源为主/ vhost.erb。 我们使用require语句,以确保包装后只得到执行的模板资源apache2安装,否则Apache所使用的目录结构可能不存在呢。

第32-35行

最后, 服务资源声明apache2服务,这是我们从应用于虚拟主机模板的资源重新启动通知。

结论

Puppet是一个强大的配置管理工具,它使用表达式定制DSL来管理服务器资源和自动执行任务。 它的语言提供了高级资源,可以为您的配置设置提供额外的灵活性; 重要的是要记住资源不是以它们被定义的相同顺序来评估的,因此,当定义资源之间的依赖关系以便建立正确的执行链时,您需要小心。

这一系列的下一个导游 ,我们将看看Chef,另一个强大的配置管理工具,它利用Ruby编程语言来自动化基础设施的管理和配置。