在Puppet中,模块是服务器配置的构建块。模块安装和配置包,创建目录,并生成用户在模块中包含的任何其他服务器更改。Puppet模块旨在执行特定任务的所有部分,例如下载Apache包,配置所有文件,更改MPM数据以及设置虚拟主机。反过来,模块被分解为扩展名为.pp
的类文件,这些文件旨在将模块简化为各种任务,并提高模块的可读性。
在本指南中,Apache和PHP模块将从头开始创建,MySQL模块将改编自Puppet Forge上的PuppetLab的MySQL模块。这些步骤将在您的服务器上创建一个完整的LAMP堆栈,并提供各种使用模块的方式的概述。
注意
本指南假设您使用的是Pbupet 设置指南中配置的Ubuntu 14.04 LTS Puppet master和CentOS 7和Ubuntu 14.04节点。如果使用不同的设置,请进行相应调整。
cd /etc/puppet/modules
sudo mkdir apache
apache
目录,创建manifests
,templates
,files
,和examples
目录:cd apache
sudo mkdir {manifests,templates,files,examples}
manifests
目录:cd manifests
从这里开始,模块将根据特定代码段的目标分成几类。在这个例子中,将有一个init.pp
类用于下载Apache包,一个params.pp
用于定义任何变量和参数,config.pp
文件用于管理Apache服务本身的任何配置文件,以及一个vhosts.pp
用于定义虚拟主机的文件。该模块还将利用Hiera数据存储每个节点的变量。
/etc/puppet/modules/apache/manifests/init.pp
class apache {
}
该文件将用于安装Apache包。但是,Ubuntu 14.04和CentOS 7下的Apache包名并不一样,因此,将使用变量进行处理:
/etc/puppet/modules/apache/manifests/init.pp
class apache {
package { 'apache':
name => $apachename,
ensure => present,
}
}
该package
资源允许管理包,用于添加,删除或确保包存在。在大多数情况下,资源的名称('apache',见上文)应为要管理的包的名称。但是,由于命名约定的不同,这个资源只是简单的命名为apache
,而使用名称引用调用包的实际名称。在上面的实例中,.name
调用尚未定义的变量$apachename
,ensure
引用则用来确保包存在。
params.pp
类就会发挥作用。虽然可以在init.pp
代码中定义这些变量,但是因为有很多变量需要在资源类型本身之外使用,使用params.pp
类可以在if
块中定义变量并在多个类中使用。创建并打开params.pp
:
/etc/puppet/modules/apache/manifests/params.pp
class apache::params {
}
在原始init.pp
类之外,每个类名都应为apache
分支。因此,这个类被称为apache::params
。双冒号后面的名称应与文件名相同。
if
块,从已经安装在Puppet master上的Facter提供的信息中提取。在本案中,Facter将用于下拉操作系统系列(osfamily
),以识别它是基于Red Hat还是基于Debian。if
块的骨架应类似于以下内容:/etc/puppet/modules/apache/manifests/params.pp
class apache::params {
if $::osfamily == 'RedHat' {
} elseif $::osfamily == 'Debian' {
} else {
print "This is not a supported distro."
}
}
一旦我们添加了已经引用的变量:
/etc/puppet/modules/apache/manifests/params.pp
class apache::params {
if $::osfamily == 'RedHat' {
$apachename = 'httpd'
} elseif $::osfamily == 'Debian' {
$apachename = 'apache2'
} else {
print "This is not a supported distro."
}
}
注意
在本指南的持续时间内,当需要将某些内容添加到参数列表中时,将提供Red Hat和Debian所需的变量,但不会显示扩展代码。可在此处查看
params.pp
的完整副本。
params.pp
文件和参数引入到init.pp
。要做到这一点,需要在类名之后、花括号({
)之前添加参数:/etc/puppet/modules/apache/manifests/init.pp
class apache (
$apachename = $::apache::params::apachename,
) inherits ::apache::params {
值字符串$::apache::params::value
告诉Puppet从apache
模块的params
类中提取值,然后是参数名称。该片段inherits ::apache::params
允许init.pp
继承这些值。
Apache有两个不同的配置文件,取决于您是在使用基于Red Hat还是基于Debian的系统。这些文件可以从服务器中拉取,或者在这里查看:httpd.conf(Red Hat),apache2.conf(Debian)。
httpd.conf
和apache2.conf
文件复制到files
目录。位于/etc/puppet/modules/apache/files/
。 KeepAlive
设置设置为Off
。需要在httpd.conf
文件中添加此设置,否则,应将以下注释添加到每个文件的顶部:/etc/puppet/modules/apache/files/httpd.conf
# This file is managed by Puppet
init.pp
文件中,使Puppet知道它们在主服务器和代理节点上的位置。为此,使用file
资源:/etc/puppet/modules/apache/manifests/init.pp
file { 'configuration-file':
path => $conffile,
ensure => file,
source => $confsource,
}
由于配置文件位于两个不同的位置,因此将为资源指定通用名称configuration-file
,并将文件路径定义为具有该path
属性的参数。ensure
确保它是一个文件。source
是另一个参数,它将调用上面创建的主文件位于Puppet master上的位置。
params.pp
文件。$conffile
与$confsource
变量需要在if
语句块中定义:/etc/puppet/modules/apache/manifests/params.pp
if $::osfamily == 'RedHat' {
...
$conffile = '/etc/httpd/conf/httpd.conf'
$confsource = 'puppet:///modules/apache/httpd.conf'
} elsif $::osfamily == 'Debian' {
...
$conffile = '/etc/apache2/apache2.conf'
$confsource = 'puppet:///modules/apache/apache2.conf'
} else {
...
根据附加参数的示例,还需要将这些参数添加到init.pp
文件中。init.pp
文件的完整副本可在此处查看。
notify
属性使用service
资源,只要配置文件发生更改,就会调用该资源:/etc/puppet/modules/apache/manifests/init.pp
file { 'configuration-file':
path => $conffile,
ensure => file,
source => $confsource,
notify => Service['apache-service'],
}
service { 'apache-service':
name => $apachename,
hasrestart => true,
}
service
资源使用已创建的参数,该参数在Red Hat和Debian系统上定义了Apache名称。hasrestart
属性将触发已定义服务的重新启动。
虚拟主机文件将以不同方式进行管理,具体取决于服务器是基于Red Hat还是Debian发行版。因此,虚拟主机的代码将被包含在if
语句块中,类似于params.pp
类中使用的语句,但包含实际的Puppet资源。下面将提供在Puppet代码中使用if
语句块的示例。
apache/manifests/
目录中,创建并打开vhosts.pp
文件。if
语句块的框架:/etc/puppet/modules/apache/manifests/vhosts.pp
class apache::vhosts {
if $::osfamily == 'RedHat' {
} elsif $::osfamily == 'Debian' {
} else {
}
}
/etc/httpd/conf.d/vhost.conf
。此文件需要在Puppet master上创建为模板。对于Ubuntu服务器,需要做同样的事情,该文件位于/etc/apache2/sites-available/example.com.conf
,使用服务器的FQDN替换example.com
。还需要在Puppet主服务器上创建此文件的模板。导航到apache模块中的templates
文件夹,然后为虚拟主机创建两个文件:对于Red Hat系统:
/etc/puppet/modules/apache/templates/vhosts-rh.conf.erb
<VirtualHost \*:80>
ServerAdmin <%= @adminemail %>
ServerName <%= @servername %>
ServerAlias www.<%= @servername %>
DocumentRoot /var/www/<%= @servername -%>/public\_html/
ErrorLog /var/www/<%- @servername -%>/logs/error.log
CustomLog /var/www/<%= @servername -%>/logs/access.log combined
</Virtual Host>
对于Debian系统:
/etc/puppet/modules/apache/templates/vhosts-deb.conf.erb
<VirtualHost *:80>
ServerAdmin <%= @adminemail %>
ServerName <%= @servername %>
ServerAlias www.<%= @servername %>
DocumentRoot /var/www/html/<%= @servername -%>/public_html/
ErrorLog /var/www/html/<%- @servername -%>/logs/error.log
CustomLog /var/www/html/<%= @servername -%>/logs/access.log combined
<Directory /var/www/html/<%= @servername -%>/public_html>
Require all granted
</Directory>
</Virtual Host>
在这些文件中使用了两个变量:adminemail
和servername
。这些变量将在每个节点的site.pp
文件中进行定义。
vhosts.pp
文件,现在可以在代码中引用创建的模板:
/etc/puppet/modules/apache/manifests/vhosts.pp class apache::vhosts {
if $::osfamily == 'RedHat' {
file { '/etc/httpd/conf.d/vhost.conf':
ensure => file,
content => template('apache/vhosts-rh.conf.erb'),
}
} elsif $::osfamily == 'Debian' {
file { "/etc/apache2/sites-available/$servername.conf":
ensure => file,
content => template('apache/vhosts-deb.conf.erb'),
}
} else {
print "This is not a supported distro."
}
}
两个分发系列都调用file
资源并在相应的分发上获取虚拟主机位置的标题。对于Debian,这再次意味着引用$servername
值。content
属性调用相应的模板。
注意
变量(例如上面的Debian文件资源的名称)需要用双引号括起来(
"
)。单引号('
)中的任何变量都完全按照写入进行解析,不会引入变量。
file
资源创建,每个资源都位于if
语句块中。完整的vhosts.conf
文件应该类似于:
/etc/puppet/modules/apache/manifests/vhosts.pp class apache::vhosts {
if $::osfamily == 'RedHat' {
file { '/etc/httpd/conf.d/vhost.conf':
ensure => file,
content => template('apache/vhosts-rh.conf.erb'),
}
file { "/var/www/$servername":
ensure => directory,
}
file { "/var/www/$servername/public_html":
ensure => directory,
}
file { "/var/www/$servername/log":
ensure => directory,
}
} elsif $::osfamily == 'Debian' {
file { "/etc/apache2/sites-available/$servername.conf":
ensure => file,
content => template('apache/vhosts-deb.conf.erb'),
}
file { "/var/www/$servername":
ensure => directory,
}
file { "/var/www/html/$servername/public_html":
ensure => directory,
}
file { "/var/www/html/$servername/logs":
ensure => directory,
}
} else {
print "This is not a supported distro."
}
}
apache/manifests/
目录,运行puppet parser
验证所有文件,以确保Puppet编码正确:sudo puppet parser validate init.pp params.pp vhosts.pp
返回结果应该为空,除非出现任何问题。
apache
模块中的examples
目录。创建一个init.pp
文件并包含创建的类。为servername
和提供变量adminemail
:
/etc/puppet/modules/apache/examples/init.pp$serveremail = 'webmaster@example.com'
$servername = 'example.com'
include apache
include apache::vhosts
puppet apply
并附加--noop
标记来测试模块:sudo puppet apply --noop init.pp
它应该不返回任何错误,并且会响应事件更新输出。如果需要在Puppet主服务器上安装和配置apache,可以不带--noop
标签再次运行puppet apply
。
manifests
文件夹(不是位于Apache模块中的文件夹)。如果您从Puppet设置指南继续本指南,则应该已经创建了一个名为site.pp
的文件。如果没有,请立即创建一个。node 'ubuntuhost.example.com' {
$adminemail = 'webmaster@example.com'
$servername = 'hostname.example.com'
include accounts
include apache
include apache::vhosts
resources { 'firewall':
purge => true,
}
Firewall {
before => Class['firewall::post'],
require => Class['firewall::pre'],
}
class { ['firewall::pre', 'firewall::post']: }
}
node 'centoshost.example.com' {
$adminemail = 'webmaster@example.com'
$servername = 'hostname.example.com'
include accounts
include apache
include apache::vhosts
resources { 'firewall':
purge => true,
}
Firewall {
before => Class['firewall::post'],
require => Class['firewall::pre'],
}
class { ['firewall::pre', 'firewall::post']: }
}site.pp
并为每个代理节点添加Apache模块。并输入adminemail
和servername
参数的变量。如果您遵循Puppet设置指南,其中的单个节点配置site.pp
将类似于以下内容:
/etc/puppet/manifests/site.pp sudo puppet agent -t
许多运行服务器所需的模块已经存在于Puppet Lab的Puppet Forge中。这使得你可以像创建的模块一样进行广泛地配置这些组件,并且可以节省时间,因为无需从头开始创建模块。
通过PuppetLabs 安装Puppet Forge的MySQL模块:
sudo puppet module install puppetlabs-mysql
这也将安装任何必备模块。
在开始为MySQL模块创建配置文件之前,考虑到您可能不希望在所有代理节点上使用相同的值,使用Hiera,Pupper支持为每个节点提供正确的数据。在本实例中,您将为每个节点提供不同的root密码,从而创建不同的MySQL数据库。
/etc/puppet
并创建Hiera的配置文件:hiera.yamlpuppet
/etc/puppet/hiera.yaml
:backends:
- yaml
:yaml:
:datadir: /etc/puppet/hieradata
:hierarchy:
- "nodes/%{::fqdn}"
- common
:backends:
下面的值定义您正在YAML中写入数据,而:datadir:
调用Hiera存储数据的目录。:hierarchy:
部分表示您的数据将保存在node
目录下的文件中,文件以节点的FQDN命名。一个common
文件将包含默认的变量。
/etc/puppet/
目录中,为hieradata
和nodes
创建目录:sudo mkdir -p hieradata/nodes
nodes
目录:cd hieradata/nodes
puppet cert
命令列出可用的节点,然后使用FQDN作为文件名称为每个节点创建YAML文件:sudo puppet cert list --all
sudo touch {ubuntuhost.example.com.yaml,centoshost.example.com.yaml}
webdata1
,自定义username
和password
。该grant
值授予用户对webdata1数据库的所有访问权限:
/etc/puppet/hieradata/nodes/ubuntuhost.example.com.yamldatabases:
webdata1:
user: 'username'
password: 'password'
grant: 'ALL'
重复第二个服务器。在此示例中,数据库名为webdata2
:
/etc/puppet/hieradata/nodes/centoshost.example.com.yaml
databases:
webdata2:
user: 'username'
password: 'password'
grant: 'ALL'
保存并关闭文件。
hieradata
目录并创建文件common.yaml
。它将用于定义root
用户的默认密码:
/etc/puppet/hieradata/common.yamlmysql::server::root\_password: 'password'如果未在其他位置定义变量,则使用common.yaml
文件。这意味着所有服务器将共享相同的MySQL root密码。这些密码也可以进行哈希处理以提高安全性。class mysql::database {
include mysql::server
create_resources('mysql::db', hiera_hash('databases'))
}mysql
模块目录并在manifests
目录创建database.pp
文件。在这里,您将定义一个将mysql::db
资源链接到Hiera数据的类。它也会调用mysql::server
类,因此不必在以后包含它:
/etc/puppet/modules/mysql/manifests/database.ppsite.pp
文件中两个节点包含include mysql::database
。php
目录modules
路径,随后创建files
,manifests
,templates
,和examples
子文件夹:sudo mkdir php
cd php
sudo mkdir {files,manifests,examples,templates}
init.pp
。因为所有要做的就是PHP服务正确安装,并且能够在启动时启动,所有代码都将包含在此文件中。class php {
package { 'php':
name: $phpname,
ensure: present,
}
package { 'php-pear':
ensure: present,
}
}因为php
程序包在Ubuntu和CentOS上具有不同的名称,所以它将再次需要使用参数进行定义。但是,因为这是我们需要的唯一参数,所以它将直接添加到init.pp
文件中:
/etc/puppet/modules/php/manifests/init.pp package
资源:
/etc/puppet/modules/php/manifests/init.ppclass php {
$phpname = $osfamily ? {
'Debian' => 'php5',
'RedHat' => 'php',
default => warning('This distribution is not supported by the PHP module'),
}
package { 'php':
name => $phpname,
ensure => present,
}
package { 'php-pear':
ensure => present,
}
}
service
资源确保PHP已启用并设置为开机启动:
/etc/puppet/modules/php/manifests/init.ppclass php {
$phpname = $osfamily ? {
'Debian' => 'php5',
'RedHat' => 'php',
default => warning('This distribution is not supported by the PHP module'),
}
package { 'php':
name => $phpname,
ensure => present,
}
package { 'php-pear':
ensure => present,
}
service { 'php-service':
name => $phpname,
ensure => running,
enable => true,
}
}include php
到sites.pp
文件中的主机中,并在代理节点上运行puppet agent -t
,以便对服务器进行任何更改。