Puppet 代码入门:清单和模块
简介
在设置代理/主配置的 Puppet 后,您可能需要一些帮助来编写 Puppet 清单和模块。为了有效地使用 Puppet,您必须了解清单和模块的构造方式。本教程涵盖了 Puppet 代码的基础知识,并将向您展示如何构建清单和模块,以帮助您开始使用 Puppet 来管理服务器环境。我们将展示使用 Puppet 在 Ubuntu 14.04 VPS 上配置 LAMP 栈的三种不同方法。
先决条件
在开始本教程之前,您必须拥有一个正常运行的代理/主 Puppet 设置。如果您还没有这个设置,请按照本教程进行操作:如何安装 Puppet 来管理您的服务器基础设施。
您还需要能够创建至少一个新的 VPS 作为 Puppet 代理节点,以便 Puppet 主节点进行管理。
创建新的代理节点
创建一个名为 “lamp-1” 的新的 Ubuntu 14.04 VPS,将其添加为 Puppet 代理节点,并在 Puppet 主节点上签署其证书请求。
Puppet 代码基础知识
在开始编写 Puppet 代码来配置我们的系统之前,让我们回顾一下一些相关的 Puppet 术语和概念。
资源
Puppet 代码主要由 资源声明 组成。资源描述了系统状态的某些内容,比如某个用户或文件应该存在,或者应该安装某个软件包。以下是一个用户资源声明的示例:
user { 'mitchell':
ensure => present,
uid => '1000',
gid => '1000',
shell => '/bin/bash',
home => '/home/mitchell'
}
资源声明的格式如下:
resource_type { 'resource_name'
attribute => value
...
}
因此,上面的资源声明描述了一个名为 ‘mitchell’ 的用户资源,具有指定的属性。
要列出 Puppet 可用的所有默认资源类型,请输入以下命令:
puppet resource --types
在本教程中,我们将涵盖一些其他资源类型。
清单
Puppet 程序称为清单。清单由 Puppet 代码组成,其文件名使用 .pp
扩展名。通过 apt 安装的 Puppet 的默认主清单是 /etc/puppet/manifests/site.pp
。
如果您已经按照先决条件 Puppet 教程的步骤进行操作,您已经编写了一个创建文件并安装 Apache 的清单。在本教程中,我们还将编写一些其他清单。
类
在 Puppet 中,类是可以在其他地方调用的代码块。使用类允许您重用 Puppet 代码,并且可以使清单的阅读更加容易。
类定义
类定义是组成类的代码所在的地方。定义类使得该类可以在清单中使用,但实际上不会评估任何内容。
以下是类 定义 的格式:
class example_class {
...
代码
...
}
上面定义了一个名为 “example_class” 的类,Puppet 代码将位于花括号之间。
类声明
当在清单中调用类时,会发生类声明。类声明告诉 Puppet 评估类中的代码。类声明有两种不同的形式:普通形式和类似资源的形式。
普通类声明 发生在 Puppet 代码中使用 include
关键字时,如下所示:
include example_class
这将导致 Puppet 评估 example_class 中的代码。
类似资源的类声明 发生在类被声明为资源时,如下所示:
class { 'example_class': }
使用类似资源的类声明允许您指定 类参数,这些参数会覆盖类属性的默认值。如果您按照先决条件教程进行操作,您已经使用了类似资源的类声明(“apache” 类),当您使用 PuppetLabs Apache 模块在 host2 上安装 Apache 时:
node 'host2' {
class { 'apache': } # 使用 apache 模块
apache::vhost { 'example.com': # 定义虚拟主机资源
port => '80',
docroot => '/var/www/html'
}
}
现在您已经了解了资源、清单和类,您可能想要了解有关模块的更多信息。
模块
模块是清单和数据(如事实、文件和模板)的集合,并且它们具有特定的目录结构。模块对于组织 Puppet 代码非常有用,因为它们允许您将代码拆分为多个清单。使用模块来组织几乎所有的 Puppet 清单被认为是最佳实践。
要将模块添加到 Puppet 中,请将其放置在 /etc/puppet/modules
目录中。
我们将涵盖编写自己的基本模块所需的详细信息。如果您想了解更多细节,请查看 PuppetLabs 模块基础知识参考指南。
开发清单
为了演示如何编写 Puppet 清单、类和模块,我们将使用 Puppet 在 Ubuntu 上设置 LAMP 栈(类似于本教程中的设置)。如果您以前从未设置过 LAMP 栈,您需要运行链接的教程,以熟悉如何手动设置。
从 LAMP 栈教程中,我们知道我们需要一个 Ubuntu 14.04 服务器,具有以下资源:
- 安装了 Apache 软件包(apache2)的 Apache 服务
- 运行的 Apache 服务(apache2)
- 安装了 MySQL 服务器软件包(mysql-server)的 MySQL 服务器
- 运行的 MySQL 服务器服务(mysql)
- 安装了 PHP5 软件包(php5)
- 一个测试的 PHP 脚本文件(info.php)
- 在安装软件包之前更新 apt
以下三个部分将展示使用 Puppet 实现类似结果(一个可工作的 LAMP 服务器)的不同方法。第一个示例将展示如何编写一个基本的清单,该清单全部在一个文件中。第二个示例将展示如何构建和使用类和模块,基于第一个示例中开发的清单。最后,第三个示例将展示如何使用现有的、公开可用的模块快速轻松地设置类似的 LAMP 栈。如果您想尝试所有三个示例以进行学习,我们建议每次从头开始使用一个新的 VPS(如先决条件中所述)。
示例 1:使用单个清单安装 LAMP
如果您以前从未编写过 Puppet 清单,这个示例是一个很好的起点。清单将在 Puppet 代理节点上开发,并通过 puppet apply
执行,因此不需要代理/主设置。
您将学习如何编写一个清单,该清单将使用以下类型的资源声明:
- exec:执行命令,如
apt-get
- package:通过 apt 安装软件包
- service:确保服务正在运行
- file:确保某些文件存在
创建清单
在一个新的 lamp-1 VPS 上,创建一个新的清单:
sudo vi /etc/puppet/manifests/lamp.pp
添加以下行来声明我们刚刚确定要使用的资源。内联注释详细说明了每个资源声明:
# 执行 'apt-get update'
exec { 'apt-update': # exec 资源命名为 'apt-update'
command => '/usr/bin/apt-get update' # 此资源将运行的命令
}
# 安装 apache2 软件包
package { 'apache2':
require => Exec['apt-update'], # 在安装之前需要 'apt-update'
ensure => installed,
}
# 确保 apache2 服务正在运行
service { 'apache2':
ensure => running,
}
# 安装 mysql-server 软件包
package { 'mysql-server':
require => Exec['apt-update'], # 在安装之前需要 'apt-update'
ensure => installed,
}
# 确保 mysql 服务正在运行
service { 'mysql':
ensure => running,
}
# 安装 php5 软件包
package { 'php5':
require => Exec['apt-update'], # 在安装之前需要 'apt-update'
ensure => installed,
}
# 确保 info.php 文件存在
file { '/var/www/html/info.php':
ensure => file,
content => '<?php phpinfo(); ?>', # phpinfo 代码
require => Package['apache2'], # 在创建之前需要 'apache2' 软件包
}
保存并退出。
应用清单
现在,您将要使用 puppet apply
命令来执行清单。在 lamp-1 上,运行以下命令:
sudo puppet apply --test
您将看到许多输出行,显示服务器状态如何更改,以匹配清单中的资源声明。如果没有错误,您应该能够访问公共 IP 地址(或域名,如果您设置了),并看到指示 Apache 和 PHP 正在工作的 PHP 信息页面。您还可以验证 MySQL 是否已安装在服务器上(尚未进行安全设置,但我们现在不打算担心这个)。恭喜!您使用 Puppet 设置了一个 LAMP 栈。
这种特定的设置并不太令人兴奋,因为我们没有利用我们的代理/主设置。当前清单当前不可用于其他代理节点,并且 Puppet 不会持续检查(每 30 分钟)我们的服务器是否处于清单描述的状态。
现在我们想将刚刚开发的清单转换为一个模块,以便您的其他 Puppet 节点可以使用它。
示例 2:创建新模块安装 LAMP
现在让我们在 Puppet 主 节点上创建一个基本模块,该模块基于示例 1 中开发的 LAMP 清单。这次我们将在 Puppet 主 节点上进行。要创建一个模块,您必须在 Puppet 的 modules
目录中创建一个目录(其名称与您的模块名称匹配),并且它必须包含一个名为 manifests
的目录,该目录必须包含一个 init.pp
文件。init.pp
文件必须只包含与模块名称匹配的 Puppet 类。
创建模块
在 Puppet master 上,创建名为 lamp
的模块的目录结构:
cd /etc/puppet/modules
sudo mkdir -p lamp/manifests
现在创建并编辑模块的 init.pp
文件:
sudo vi lamp/manifests/init.pp
在这个文件中,通过添加以下行来为名为 “lamp” 的类添加一个代码块:
class lamp {
}
复制之前创建的 LAMP manifest 的内容(或者从上面的示例 1 复制),并粘贴到 lamp 类的代码块中。在这个文件中,你创建了一个名为 “lamp” 的类定义。此类中的代码在此时不会被评估,但可以被声明。此外,因为它符合定义模块的 Puppet 约定,其他 manifest 可以作为模块访问这个类。
保存并退出。
在主 Manifest 中使用模块
现在我们已经设置了一个基本的 lamp 模块,让我们配置我们的主 manifest 来使用它在 lamp-1 上安装 LAMP 栈。
在 Puppet master 上,编辑主 manifest:
sudo vi /etc/puppet/manifests/site.pp
假设文件是空的,添加以下 node 代码块(用 Puppet 代理的主机名替换 “lamp-1”):
node default { }
node 'lamp-1' {
}
node 代码块允许你指定只适用于特定代理节点的 Puppet 代码。default 节点适用于没有指定节点代码块的每个代理节点–我们将其留空。lamp-1 节点代码块将适用于你的 lamp-1 Puppet 代理节点。
在 lamp-1 节点代码块中,添加以下代码来使用我们刚刚创建的 “lamp” 模块:
include lamp
现在保存并退出。
下次 lamp-1 Puppet 代理节点从主服务器拉取配置时,它将评估主 manifest 并应用指定 LAMP 栈设置的模块。如果你想立即尝试它,可以在 lamp-1 代理节点上运行以下命令:
sudo puppet agent --test
完成后,你将看到一个基本的 LAMP 栈已经设置,就像示例 1 一样。要验证 Apache 和 PHP 是否正常工作,请在 lamp-1 的公共 IP 地址中使用 web 浏览器:
http://lamp_1_public_IP/info.php
你应该会看到 PHP 安装的信息页面。
请注意,你可以通过在其他节点代码块中声明它来重用你创建的 “lamp” 模块。使用模块是促进 Puppet 代码重用的最佳方式,也有助于以逻辑方式组织你的代码。
现在我们将向你展示如何使用预先存在的模块来实现类似的设置。
示例 3:使用预先存在的模块安装 LAMP
在 Puppet Forge 上有一个公开可用模块的存储库,当尝试开发自己的基础架构时,这些模块可能会很有用。Puppet Forge 模块可以通过内置的 puppet module
命令快速安装。恰好在这里有安装和维护 Apache 和 MySQL 的模块。我们将演示如何使用它们来帮助我们设置 LAMP 栈。
安装 Apache 和 MySQL 模块
在你的 Puppet master 上,安装 puppetlabs-apache
模块:
sudo puppet module install puppetlabs-apache
你将看到以下输出,表示模块已正确安装:
Notice: Preparing to install into /etc/puppetlabs/puppet/modules ...
Notice: Downloading from https://forgeapi.puppetlabs.com ...
Notice: Installing -- do not interrupt ...
/etc/puppet/modules
└─┬ puppetlabs-apache (v1.0.1)
├── puppetlabs-concat (v1.0.0) [/etc/puppet/modules]
└── puppetlabs-stdlib (v3.2.0) [/etc/puppet/modules]
还要安装 puppetlabs-mysql
模块:
sudo puppet module install puppetlabs-mysql
现在 apache 和 mysql 模块已经可以使用了!
编辑主 Manifest
现在让我们编辑我们的主 manifest,以便使用新模块来安装我们的 LAMP 栈。
在 Puppet master 上,编辑主 manifest:
sudo vi /etc/puppet/manifests/site.pp
假设文件是空的,添加以下节点代码块(如果你遵循示例 2,只需删除 lamp-1 节点代码块的内容):
node default { }
node 'lamp-1' {
}
在 lamp-1 节点代码块内,使用类似资源的类声明来使用 apache 模块(内联注释解释了每一行):
class { 'apache': # 使用 "apache" 模块
default_vhost => false, # 不使用默认虚拟主机
default_mods => false, # 不加载默认模块
mpm_module => 'prefork', # 使用 "prefork" mpm_module
}
include apache::mod::php # 包含 mod php
apache::vhost { 'example.com': # 创建名为 "example.com" 的虚拟主机
port => '80', # 使用端口 80
docroot => '/var/www/html', # 将文档根目录设置为 /var/www/html
}
apache 模块可以传递参数来覆盖模块的默认行为。我们传递了一些基本设置,禁用了模块创建的默认虚拟主机,并确保我们创建了一个可以使用 PHP 的虚拟主机。有关 PuppetLabs-Apache 模块的完整文档,请查看其自述文件。
使用 MySQL 模块类似于使用 Apache 模块。由于我们实际上没有使用数据库,因此我们将保持简单。在节点代码块内添加以下行:
class { 'mysql::server':
root_password => 'password',
}
与 Apache 模块一样,可以通过传递参数来配置 MySQL 模块(完整文档在此)。
现在让我们添加文件资源,以确保 info.php 被复制到正确的位置。这次,我们将使用 source 参数来指定要复制的文件。在节点代码块内添加以下行:
file { 'info.php': # 文件资源名称
path => '/var/www/html/info.php', # 目标路径
ensure => file,
require => Class['apache'], # 需要使用 apache 类
source => 'puppet:///modules/apache/info.php', # 指定要复制的文件位置
}
这个文件资源声明与之前略有不同。主要区别在于我们指定了 source 参数,而不是 content 参数。Source 告诉 Puppet 复制一个文件,而不仅仅指定文件的内容。指定的源 puppet:///modules/apache/info.php
由 Puppet 解释为 /etc/puppet/modules/apache/files/info.php
,因此我们必须创建源文件,以便这个资源声明能够正常工作。
保存并退出 site.pp
。
使用以下命令创建 info.php
文件:
sudo sh -c 'echo "<?php phpinfo(); ?>" > /etc/puppet/modules/apache/files/info.php'
下次 lamp-1 Puppet 代理节点从主服务器拉取配置时,它将评估主 manifest 并应用指定 LAMP 栈设置的模块。如果你想立即尝试它,可以在 lamp-1 代理节点上运行以下命令:
sudo puppet agent --test
完成后,你将看到一个基本的 LAMP 栈已经设置,就像示例 1 一样。要验证 Apache 和 PHP 是否正常工作,请在 lamp-1 的公共 IP 地址中使用 web 浏览器:
http://lamp_1_public_IP/info.php
你应该会看到 PHP 安装的信息页面。
结论
恭喜!您已经使用 Puppet 设置了 Ubuntu 14.04 LAMP 栈。
现在您已经熟悉了 Puppet 代码的基础知识,并且能够编写基本的清单和模块,您应该尝试使用 Puppet 来配置您环境的其他方面。
一个很好的起点是使用 Puppet 来管理您的系统用户和应用程序配置文件。请记住,如果您使用 Puppet 来管理资源,您必须在 Puppet 主服务器上对这些特定资源进行更改,否则它们将在代理节点进行周期性目录拉取请求时被覆盖。
祝您好运!