指定资源的依赖关系
Remove wrapper, open mouth, insert muffin, eat.
— Instructions on 7-11 muffin packaging
为确保事物以正确的顺序发生,你可以在 Puppet 中指定一个资源依赖另一个资源, 例如:你必须先安装软件包 X 然后再启动它提供的服务,因此应该标记这项服务依赖于软件包 X。 Puppet 会按要求的顺序排出它遇到的所有依赖。
在一些配置管理系统中,资源按照你的书写顺序被应用,换句话说,资源被应用的顺序是隐式的。 Puppet 则不是这种情况,资源或多或少以一种随机(但一致)顺序被应用, 除非你明确地使用依赖关系指出应用的顺序。 一些人更喜欢隐式的方式,因为你可以按照你需要的执行顺序书写资源定义, 并且这就是它们被执行的方式。
另一方面,许多情况下资源的顺序无关紧要。使用隐式风格的系统时, 你不能明确地告诉系统,资源 B 是否被写在了资源 A 之后,由于资源 B 依赖于 A; 或者说书写的顺序是否正确,即资源 A 写在了资源 B 之前。 这使得重构更加困难,因为移动资源有可能会打破一些隐式的依赖关系。
虽然 Puppet 会让你多做一点儿工作,就是预先指定依赖关系, 但是这样产生的代码会更清晰且更易于维护。让我们看一个例子。
操作步骤
使用如下的内容创建一个新文件 /etc/puppet/modules/admin/manifests/ntp.pp:
class admin::ntp { package { "ntp": ensure => installed, } service { "ntp": ensure => running, require => Package["ntp"], } file { "/etc/ntp.conf": source => "puppet:///modules/admin/ntp.conf", notify => Service["ntp"], require => Package["ntp"], } }
复制已经存在的 ntp.conf 文件到 Puppet 的如下目录:
# cp /etc/ntp.conf /etc/puppet/modules/admin/files
在 nodes.pp 中将 admin::ntp 类添加到你的服务器:
node cookbook { include admin::ntp }
现在删除系统中已存在的 ntp.conf 文件:
# rm /etc/ntp.conf
运行 Puppet:
# puppet agent --test info: Retrieving plugin info: Caching catalog for cookbook.bitfieldconsulting.com info: Applying configuration version '1302960655' notice: /Stage[main]/Admin::Ntp/File[/etc/ntp.conf]/ensure: defined content as '{md5}3386aaad98dd5e0b28428966dac9e1f5' info: /Stage[main]/Admin::Ntp/File[/etc/ntp.conf]: Scheduling refresh of Service[ntp] notice: /Stage[main]/Admin::Ntp/Service[ntp]: Triggered 'refresh' from 1 events notice: Finished catalog run in 2.36 seconds
工作原理
在本例中演示了两种类型的依赖: require 和 notify。在第一种情况中, ntp 服务要求 ntp 包资源首先被应用:
service { "ntp":
ensure => running,
require => Package["ntp"],
}
在第二种情况中,NTP 的配置文件设置成了 notify(通知)ntp 服务;换句话说, 一旦发现配置文件有变化,Puppet 就应该使用新的配置文件重新启动 ntp 服务:
file { "/etc/ntp.conf":
source => "puppet:///modules/admin/ntp.conf",
notify => Service["ntp"],
require => Package["ntp"],
}
这意味着服务依赖于配置文件以及所安装的软件包,Puppet 会按照如下的正确顺序来应用这三个资源:
Package["ntp"] -> File["/etc/ntp.conf"] ~> Service["ntp"]
事实上,这是指定相同依赖关系链的另一种方法。添加上面这行到你的配置清单中, 就会产生和上例中使用 require 和 notify 参数的同样效果 (-> 表示 require,~> 表示 notify)。然而,我更喜欢使用 require 和 notify, 因为依赖关系被定义成了资源的一部分,因此更容易看清将会发生什么。 不过,对于复杂的依赖关系链,你可能想使用 -> 符号来代替。
更多用法
你也可以指定一个资源依赖于某个类:
require => Class["my-apt-repo"]
你不仅可以指定资源和类之间的依赖关系,甚至可以指定 collections 之间的依赖关系:
Yumrepo <| |> -> Package <| provider == yum |>
这是一种功能强大的表达方式,所有 provider 是 yum 的 package 资源被应用之前, 所有的 yumrepo 资源首先都应该被应用。
历史说明:
在 Puppet 2.7 版本之前, 所有资源编目都以非确定性的方式被应用, 这意味着每次 Puppet 运行资源的顺序都会不同。这可能会导致一些有趣的问题, 比如一个 Puppet 配置清单在一台机器上能运行成功而在另一台机器上却运行失败。 经过 Puppet Labs 的努力,现在这种情况已经不会发生。现在 Puppet 既保证可靠成功,又保证可靠失败("either succeed reliably, or fail reliably")。 如果你还在使用早期版本并且遇到了这种问题,请更新到新版本。