puppet 应用

使用Puppet
前面看过Puppet语言的句法了,并且说了如何使用句法去表达配置,这次我们开始看一下Puppet的能力和怎么样在你的结点中充分利用这门语言去接合实际的配置。我们开始通过演示如何使用Puppet在一个真实的环境中配置你的结点,我们将充分利用(三)中我们讲过的句法。
所有的这些例子表现了在你的环境中实现Puppet的一种方式.这些例子被设计用做给你一个如何实现生产Puppet能够工作的主意,一些例子表现出一些最好的实践准则,但是还有一些是关于使用Puppet去使你配置清晰的主意。

Manifest Organization
在我们开始配置我们的环境之前,我们需要去看一下Puppet是如何管理和存储它的配置的,像你记得的那样,我们的资源、classes、definitions 都存储在manifest文件中。一个特殊的manifest文件叫做site manifest,这个文件是我们配置的核心,当启动Puppet master守护进程的时候,site manifest文件默认存储在/etc/puppet/manifest/site.pp这个文件中,需要表现依照句法判定配置是否正确。

Importing Manifests

如果我们把配置文件都放在site.pp文件中。它将很快就变得很复杂并且很难去管理,因此,我们把配置文件存储在多个文件中,我们把site manifest文件看作一个金字塔的顶点。在这个文件中,其他的manifests和其他配置定义必须被引用,就像这样:
import "templates.pp"
import "nodes.pp"
import "classes/*"
import "groups/*"
import "users/*"
import "os/*"
我们使用了5个import语句,第一我们引入了templates.pp和node.pp,你不需要去指明.pp扩展,默认的Puppet将添加.pp扩展给任意的引入的那些没有扩展的文件。然后我们引入了3个子文件夹:groups,users和os,×代表所有的.pp文件.
我们也可以使用site.pp文件建立一个默认的文件备份或者其他默认类型的文件,像这样:
filebucket { main: server => puppet }
File { backup => main }        
我们定义了一个默认的filebucket 并且告诉文件类型总是把文件备份到filebucket里面
我们也可以将一个我们引入到site.pp文件的结构应用到这个文件,下面我展示一个关于文件结构和目录的一个例子。
Structure                      Description
/manifests/                    The manifest root directory
/manifests/site.pp             The primary manifest file
/manifests/templates.pp        Contains template nodes
/manifests/nodes.pp            Contains node definitions
/manifests/definitions/        Houses all definitions
/manifests/groups/             Contains manifests configuring groups
/manifests/os/                 Contains classes designed to configure nodes  with particularoperating systems
/manifests/users/              Contains manifests configuring users
/manifest/files/               Contains file server modules for Puppet distributable files
/manifests/templates/classname ERB templates contained in subdirectories named after the class that uses the template

manifestdir = $confdir/manifests
还有一些人把他们的mainfests放到/var/puppet文件目录下,你必须选一个适合你环境和标准的位置,我们也可以这样实现和改变site.pp的位置,使用manifest配置项
manifest = $manifestdir/site.pp
这个manifest项默认值为$manifestdir/site.pp

Managing Manifests with Subversion
版本控制工具是管理大量的manifest最好的工具,我们可以使用Subversion,svn是一个开源的版本控制工具。首先创建一个版本库
$ svnadmin create /usr/local/svn/puppet
然后我们添加Puppet目录到版本库里面
$ svn import puppet file:///usr/local/svn/puppet -m "初始导入Puppet结构"
Adding  puppet/site.pp
Adding  puppet/template.pp
Adding   puppet/nodes.pp
...
Committed revision 1.
取出一个工作副本
$ svn checkout file:///usr/local/svn/puppet /etc/puppet/manifests
然后我们把做得改变更新到版本库中
$ cd /etc/puppet/manifests
$ svn commit -m "Added firewall node"
Defining Nodes
我们首先来配置结点,我们开始结点定义,为了简单起见,我们将问你的结点按类型分类,建立一些模板,
我们将分别问不同的服务建立不同的模板,我们放置一个叫做templates.pp的文件,但是我们必须在site.pp中引入这个文件。
node basenode {
case $operatingsystem {
fedora: { include fedora }
debian: { include debian }
default: { include fedora}
}
include baseapps, sshd
}
node default inherits basenode {}
node webserver inherits basenode {
include apache
}
node dbserver inherits basenode {
include mysql
}
node mailserver inherits basenode {
include postfix
}
我们已经创建了一个我们的模板结点,首先是basenode,配置将应用到我们所有结点,在我们的basenode我们利用了一个fact $operatingsystem为了包含一个基于操作系统的结点,比如,如果Facter 返回的值是fedora ,fedora class 将被包含进来。
我们已经定义了一个默认的node,它继承basebode,这个默认的node适用于任何没用特殊声明的结点,然后我们创建了3个模板,webserver,dbserver,mailserver他们都继承basenode并且添加他们自己的classes,在目前阶段,每个模板中仅仅包含一个少数的class
这有一个关于子类和父类之间继承的二者择一的方法就是使用include函数,这个方法适合那些继承有变量范围的,如:
class baseclass {
case $operatingsystem {
fedora: { include fedora }
debian: { include debian }
default: { include fedora}
}
include baseapps, sshd
}
node default {
include baseclass
}
class webserver {
include baseclass
include apache
}
class dbserver {
include baseclass
include mysql
}
class mailserver {
include baseclass
include postfix
}
这个方法中,我们定义了一个class叫做baseclass而不是一个base结点,这个class然后包含了所有的后来的类。现在我们为我们管理的结点添加结点定义,我们创建了一个文件叫做node.pp用来存储结点,但要在site.pp中引入nodes.pp
node  'puppetmaster.testing.com' inherits basenode {}
node  'web.testing.com' inherits webserver {}
node  'db.testing.com' inherits dbserver {}
node  'mail.testing.com' inherits mailserver {}

Managing Users and Groups

一旦我们创建了结点,我们就要为我们的结点创建用户和组,Puppet推荐所有的用户和组作为虚拟的资源被创建,虚拟的资源不自动在你结点上配置,但是需要详细的应用,你可以在类型前面加上@来确认虚拟资源.
虚拟资源对用户和组都是很有用的,一旦在Puppet上这是因为一个资源只能够被管理,所以我们不能够同时在fedora和debian classes中配置一个名为sysadmin的用户,使用虚拟资源,我们能够创建一个sysadmin用户作为一个虚拟资源,然后我们可以在每个class中进行实现,我们可以在组中做同样的事,
我们开始定义两种类型的用户,第一类用户和功能有关,比如我们的sysadmin用户,或者用户属于employees和administrators,这些用户将被分组到一个单独的叫做virt_users的class并且包含在一个virt_users.pp的文件里面。第二种用户是那些被用做应用、服务、守护进程的用户,这些用户被分到他们自己的class里面,每一个类将前缀都是user_,比如user_apache.每一个用户class 将在它的文件中被指明。
我们将组分为相同的类型,用相同的模型来管理他们,所以的组都和用户相关并且被包含到一个叫做virt_group的class中,并且存放在一个名为vitr_groups.pp的文件中。组和用户类似,均以group_前缀开头,比如group_apache.我们要把users和groups的文件夹在site.pp中进行引入,确保所有的用户和组都能被加载
import "groups/*"
import "users/*"

Managing Users

我们看一部分的virt_users这个类,只显示我们的两个用户

class virt_users {
@user {
ensure => "present",
uid => "1001",
gid => "1000",
comment => "Jane Smith",
home => "/nfs/IT/home/jsmith",
shell => "/bin/bash",
}
@user {
ensure => "present",
uid => "1002",
gid => "1000",
comment => "Mary Jones",
home => "/nfs/IT/home/mjone",
shell => "/bin/bash"
}
}
看一些virt_groups这个类

class virt_groups {
@group { “staff”:
gid => "1000",
ensure => present
}
@group { "administration":
gid => "1501"
ensure => present   
}
@group { "mail_team":
gid => "1502",
ensure => present        
}
}
如何实现这些用户和组呢,首先我们我们实现这个用户和组都叫做staff,他存储在我们的class staff中存在我们的classer文件夹中,文件叫做staff.pp,我们将virt_users和virt_groups的类包含进来,确保Puppet知道去哪找用户和组.

class staff {
include virt_users,virt_groups
realize(
Group["staff"],
User["jsith"],
User["mjones"]
)
}
我们能在我们的basenode模板中确保组和用户在每个结点上都创建,结点必须继承这个模板结点。
node basenode {
case $operatingsystem {
fedora: { include fedroa }
debian: { include debian }
default: { include fedora }     
}
include baseapps,sshd,staff
}
但是我们如果也想我们的administration组也被包含在每个结点中,我们将创建一个叫做administrators的类用来实现administration的用户组然后添加用户到这个组,我们存储到一个叫做administrators.pp的文件中,放到classes文件夹中,然后我们将这个class包含到nodes.pp这个文件中的basenode类当中
class administrators inherts virt_users {
realize(
Group["administration"]
)
User["jsmith"] {groups => "administration" }
}   

node basenode {
case $operatingsystem {
fedora: { include fedora }
debian: { include debian }
default: { include fedora}
}
include baseapps, sshd, staff, administrators
}
我们实现了添加用户jsmith到administration组中,为了实现他,administrators 类继承了virt_users这个类,现在administration组将被创建在所有的结点和模板上,继承basenode 结点模板将jsmith加入到组,我们也可以在其他的类中实现这些用户,比如 mjone是一个mail administrator,我们将为mail administrators创建一个类存储在class/mail_team.pp,并且把mailserver模板结点包含进去,像这样:
class mail_team inherits virt_users {
realize(
Group["mail_team"]   
)
User["mjones"] { groups => "mail_team" }
}
node mailserver inherits basenode {
include postfix
include mail_team
}
这里mail_team组将被实现并且被mailserver结点模板包含,我们将mjone加入了mail_team组中,现在所有的结点,现在每个结点只要继承mailserver 就实现了将mjones用户添加到了mail_team组中了。
我们也可以创建但用户和组做特殊的目的,比如一个用户和组要用来跑一个守护进程或一个应用,例子如下:
class mysql_user {
user{ "mysql":
ensure => "present",
uid => "501",
gid =>  "501",
comment => "MYSQL",
home => "/var/lib/mysql",
shell => "/sbin/nologin",   
}   
}
class mysql_group {
group { "mysql":
gid => "501",
ensure => present
}
}
当我们配置合适的服务时将user和group包含进来就行了。

File Serving

在我们在结点上配置这个服务之前,我们看一些Puppet是如何进行文件服务的,puppet能做为一个文件服务器向结点去传送文件在需要时,这个文件服务是分布式文件。
Puppet的文件服务也有一个服务器和客户端,服务器是配置初始化守护进程。客户端功能是从服务器端接受文件。你可以区别一个Puppet文件服务通过文件资源类型像这样:
file { "httpd.conf":
source => "puppet://puppetmaster/httpd/conf/httpd.conf"
}
我们开始配置我们的文件服务,文件服务是由fileserver.conf这个配置文件控制的,默认存放在/etc/puppet文件夹中。在master守护进程启动的时候你可以使用一个--fsconfig的标志指明一个位置,象这样:
puppetmasterd --fsconfig /usr/local/etc/puppet/fileserver.conf
这个配置文件中定义了文件的路径和访问控制,看下面的一个例子
[configuration]
path /etc/puppet/manifests/files/configuration
allow *.testing.com
deny *.production.com
上面的例子中每一个path叫做一个module,这个module名字就是configuration.modules的作用就是允许Puppet去抽象出简单的文件系统的配置和路径,path指明了master中服务文件存放的地方,path中可以包含%h,%d和%H,它们分别代表客户端的主机名,域名,严格的域名,所有的被Puppet客户端使用的SSL证书都是基于主机和域名的,它允许你指明基于这个名字特别的文件去下载,如:
path /etc/puppet/manifests/files/%h
当客户端请求时会根据主机名生产不同的路径
/etc/puppet/manifests/files/web/filename
/etc/puppet/manifests/files/db/filename
/etc/puppet/manifests/files/mail/filename
也可以通过deny,和allow去拒绝或允许客户端下载文件。
如果你想在configuration module去检索一个文件,可以这样
file { "/etc/nsswitch.conf":
source => "puppet://puppetmaster.configuration/nsswitch.conf"
}
我们已经从Puppet master中检索出了nsswitch.conf,我们还可以下载整个文件夹的内容
file { "/etc/pam.d":
source => "puppet://puppetmaster/configuration/pam.d",
recurse => "true"
}
这次我们指明的是一个文件夹,并且这个文件夹在文件服务器上,recurse这个属性告诉Puppet所有的包含在原目录的文件应该被检索并且下载到目标结点上。

Modularizing Our Configuration
现在我们已经配置了基本的结点和介绍了用户管理以及文件服务,我们需要向我们的结点上添加一些服务像mail,databases,和web服务,现在我们在我们的db.testing,com结点上添加mysql服务,在mail.testing.com添加Postfix服务,在www.testing,con结点上添加apache服务
为了添加这些服务,我们开始使用Puppet更厉害的特性:modules.Modules是配置文件的集合manifest,templates ,files都能被复用并且是分布式的。比如除了为安装和管理mysql去创建单独的class。我们将创建一个mysql module。
为什么要用module呢? 如果是你配置的应用,守护进程,或函数包含很多类、文件或模板。最简单的方法就是将这些资源放到一个包里面,Modules使管理配置文件的集合更简单和更结构化。
Modules组织起来很简单。他们存储在一个指明的文件夹下,modulepath的配置在puppet.conf中指出,默认在$confdir/modules 和 /usr/share/puppet/modules目录,我们可以指出多个module路径用冒号隔开,如:
modulepath $confdir/modules:/usr/share/puppet/modules: ➥
/usr/local/share/puppet/modules
引入的时候使用
import "mysql"
Puppet是如何知道加载什么资源的呢,每一个module被用一个文件夹去进行组织的,调用一个init.pp的文件进行初始化,每一个module至少应该有下面的这些目录结构
module_path/
module_name/
module_name/manifests/
module_name/manifests/init.pp
当引入一个module时init.pp文件是自动处理的,init.pp应该被放到默认的module中
/etc/puppet/modules/mysql/manifests/init.pp
这个init.pp有两重的功能,它包含了一个核心的classes被用做提供一个引入类和定义的位置,它应该被放到manifests文件夹下面,下面是一个init.pp文件的例子
class mysql {
package { "mysql-server":
...
}
service { "mysqld":
...
}
}
我们声明了一个叫做mysql的class在这里我们配置了package和service的资源,所以当我们引入一个module的时候,比如是mysql module,Puppet将在所以的包含mysql的路径中进行查找,它将查出来的manifests文件夹下的init.pp文件并且加载它的内容.
Puppet也允许一些聪明的命名方法使使用模块更加容易,创建一个mysql名空间,使用这个名空间,比如,mysql module创建了一个名空间叫做mysql,使用这个名空间,我们能够很容易的在我们的模块中定义和引用其他的class,比如我们要在mysql module里面添加一个叫做server的class,为了做到这样,我们需要定义一个叫做mysql::server的类并且存储在一个叫做server.pp的文件中,我们使用这个模块只需要简单地这样写:
include mysql::server
Puppet会认出它的名空间并且会在正确的模块和文件中去加载这个类
名空间的魔法功能也可以扩展到模板和文件,为了充分利用这个特性,我们在root模块下创建了两个附加的目录,叫做templates和files,这些目录应该包含这个模块下的任意templates和任意文件,这样你的模板就能够通过指定模块名和模板的名字被引用了
template("mysql/my.cnf.erb")
Puppet将会自动的在正确的模块路径下去加载需要的模板。
在你模块包含的文件能够使用Puppet的文件服务的功能,每一个模块自动创建它自己的文件服务模块,并且加载任意模块文件路径下的存储的文件,比如在你的mysql模块,文件能使用source属性被使用
source => "puppet://puppetmaster/mysql/my.cnf"
这将会到mysql模块下的文件目录下去找my.cnf,在你的fileserver.conf中,那要定义一个特殊的文件模块叫做modules,这个允许你去进行访问控制,定义这个文件模块没用path语句,限制文件访问在所有的模块中。

MySQL Module

我们看一下我们第一个module的例子,mysql,我们将在/etc/puppet/modules目录下面存储我们的结构,结构就是这样:
/etc/puppet/modules/mysql
/etc/puppet/modules/mysql/manifests/init.pp
/etc/puppet/modules/mysql/files/my.cnf
我们包含了init.pp和一个其他的文件--配置文件 my.cnf.
init.pp文件
class mysql {
$packagelost = ["mysql","mysql-server","mysql-libs"]
package { $packagelist:
ensure => installed }
file { "/etc/my.cnf":
owner => "root",
group => "root",
mode => "0644",
replace => true,
source => "puppet:///mysql/my.cnf",
require => $Package["mysql-libs"]
}
service { mysqld:
enable => "true",
ensure => "running",
require => File["/etc/my.cnf"]
}
}
我们看到了我们的mysql模块包含3个资源,第一个是一个包资源,为每个结点的mysql安装了3个包,第二个资源是一个文件类型的资源,它从mater 服务器上检索my.cnf配置文件,我们在source属性中未包含master的名字,取代它的是puppet:///,这个用来告诉Puppet自己插入服务器的名字,这个文件资源也使用require属性告诉Puppet在文件检索之前必须加载mysql-libs,第三个资源是mysqld服务,它有一个require属性File["/etc/my.cnf"]

Postfix Module
我们的下一个模块将安装和管理一台Postfix mail 服务器,它在PostFix模块中是这样组织结构的
/etc/puppet/modules/postfix
/etc/puppet/modules/postfix/manifests/init.pp
/etc/puppet/modules/postfix/manifests/postfix_files.pp
/etc/puppet/modules/postfix/files/aliases.db
/etc/puppet/modules/postfix/files/main.cf
/etc/puppet/modules/postfix/files/master.cf
我们指出了init.pp文件像mysql模块一样,我们在init.pp中包含了所有的配置文件
init.pp

class postfix {
$mailadmin = "postmaster@$domain"
$packagelist = ["postfix.$architecture", "postfix-pflogsumm.$architecture"]
package { $packagelist:
ensure => "installed"
}
postfix::postfix_files {
"/etc/aliases.db":
mode
=> "0640",
source => "aliases.db";
"/etc/postfix/main.cf":
source => "main.cf";
"/etc/postfix/master.cf":
source => "master.cf"
}
service { "postfix":
enable => "true",
ensure => "running",
require => Package["postfix.$architecture"]
}
cron { pflogsumm:
hour
=> 2,
minute => 15,
user
=> mail,
command => "/usr/sbin/pflogsumm -d yesterday /var/log/maillog | ➥
mail -s 'pflogsumm from $fqdn' $mailadmin",
require => Package["postfix-pflogsumm.$architecture"]
}
}
我们定义了一个类叫postfix,在这个class里面我们声明一些资源和两个变量,第一个变量是$mailadmin,为每个结点定义了mail 管理员,它使用$domain这个fact去填充它的属性,第二个参数是一个包列表的数组,这个包列表使用了另一个fact。$architecture去确保每个结点都安装上了合适的包。然后我们定义了一些资源去管理我们的Postfix配置,我们首先安装的是postfix和postfix-pflogsum包,然后我们从我们的文件服务器上检索配置文件,为了做到这样,我们为创建的做了定义,我们必须定义postfix::postfix_files,它的定义如下:
define postfix::postfix_files($owner = root, $group = root, $mode = 644, ➥
$source, $backup = false, $recurse = false, $ensure = file) {
file { $name:
mode
=>
owner
=>
group
=>
backup =>
recurse =>
ensure =>
require =>
source =>
}
$mode,
$owner,
$group,
$backup,
$recurse,
$ensure,
Package["postfix.$architecture"],
"puppet:///postfix/$source"
}
我们确保Postfix服务已经启动,最好我们添加一个cron job使形成pflogsumm报告,并发送出去,在我们的cron job中我们使用$fqdn这个fact和我们的$mailadmin变量

Apache Module

最后一个module我们将要创建的是apache模块,安装和管理apache模块,Apache模块的结构是这样的:
/etc/puppet/modules/apache
/etc/puppet/modules/apache/manifests/init.pp
/etc/puppet/modules/apache/manifests/virtual_host.pp
/etc/puppet/modules/apache/manifests/apache_files.pp
/etc/puppet/modules/apache/files/httpd.conf
/etc/puppet/modules/apache/templates/virtual_host.erb
我们已经定义了一个init.pp的文件,一个文件叫做vitrual_host.pp这个文件中包含一个定义允许我们创建虚拟主机,apache_files.pp文件包含了apache::apache_files这个类,它提供了一些文件管理的快捷方式.很像postfix模块的中的postfix::postfix_files这个类,在文件目录中我们也创建了httpd.conf这个配置文件。最终在我们模板目录里面我们虚拟主机的模板叫做virtual.erb。我们来看一下init.pp为这个模块包含的核心配置文件

class apache {
$packagelist = ["httpd","webalizer","mod_ssl"]
package { $packagelist:
ensure => "installed"
}
apache::apache_files {
"/etc/httpd/conf/httpd.conf":
source => "puppet:///apache/httpd.conf"   
}
service { "httpd":
enable => "true",
ensure => "running",
hasrestart => "true",
hasstatus => "true",
require => Package["httpd"]
}
}
我们定义了apache 类,类中安装了我们需要的Apache包。安装了httpd.conf的配置文件,然后确保httpd服务能够启动和运行,你也会注意到我们在服务上指明了hasrestart和hasstatus的属性,这告诉Puppet服务的脚本支持restart和status的命令,这就让Puppet知道init脚本有很多功能,使其于脚本的交互更加灵活,下面我们看一下apache::apache_file的定义
define apache::apache_files($owner = root,$group = root,$mode = 0644,$source,$backup = false,$recurse = false, $ensure = $file) {
file { $name:
mode => $mode,
owner => $owner,
group => $group,
backup => $backup,
recurse => $recurse,
ensure => $ensure,
require => Package["httpd"],
source => "puppet:///httpd/$source"
}
}
最后定义apache::virtual_host允许我们去在web服务器上创建新的虚拟主机
define apache::virtual_host($ip,$ensure = "enable") {
$file = "/etc/httpd/conf.d/$name.comf"
$document_root = "/var/www/html/$name"
file { $file:
ensure => $ensure ? {
enable => present,
disable => absent},
content => template("apache/virtual_host.erb"),
notify => Service["httpd"]        
}
file { $document_root:
ensure => $ensure ? {
enable => directory,
disable => absent} ,
require => File["$file"]        
}
}
apache模块包含了apache::virtual_host定义并且允许我们定义一个或者多个虚拟主机,那麽我们应该怎么使用这个定义呢?我们看下面的例子
node 'web.testing.com' inherits webserver {
apache::virtual_host { "test1.testing.com":
ip => "192.168.0.1"
}
apache::virtual_host { "test2.testing.com":
ip => "192.168.0.2"
}
}
我们定义了web.testing.com结点,我们调用apache::virtual_host定义2次,每次基于virtual_host.erb模板在/etc/httpd/conf.d/目录下创建一个配置文件,virtual_host.erb内容如下:
<VirtualHost <%= ip %>>
DocumentRoot <%= document_root %>
ServerName <%= name %>
</VirtualHost>
这个模板使用document_root和ip变量,apache::virtual_host定义如下:
<VirtualHost 192.168.0.1>
DocumentRoot /var/www/html/test1.testing.com
ServerName test1.testing.com
</VirtualHost>
然后为每一个虚拟主机的文件创建一个目录,最后触发httpd重新加载,如果你想移出一个虚拟主机,你可以这样定义:
virtual_host { "test1.testing.com":
ip => "192.168.0.1",
ensure => disable
}
这将移出test1.testing.com的配置文件和相关的目录,httpd服务将使用新的配置文件进行重新启动
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值