使用虚拟资源
什么是虚拟资源(Virtual Resource),我们为什么需要它们? 下面我们来看一个可能会使用虚拟资源的典型例子。 你负责管理 facesquare
和 twitstagram
两个应用程序,他们都是运行在 Apache 上的 Web 应用程序。 facesquare
的定义看起来可能像这样:
class app::facesquare { package { "apache2-mpm-worker": ensure => installed } }
twitstagram
的定义看起来可能像这样:
class app::twitstagram { package { "apache2-mpm-worker": ensure => installed } }
一切都很好,直到你需要将两个应用程序同时应用到单台服务器上:
node micawber { include app::facesquare include app::twitstagram }
现在 Puppet 会出错,因为你试图用相同的名字 apache2-mpm-worker
定义两个 package
资源。 错误输出信息如下:
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Duplicate definition: Package[apache2-mpm-worker] is already defined in file /etc/puppet/modules/app/manifests/facesquare.pp at line 2; cannot redefine at /etc/puppet/modules/app/manifests/twitstagram.pp:2 on node cookbook.bitfieldconsulting.com
你可以从其中的一个类中移除重复的包定义,但是这样话,如果试图在另一个服务器包含 app
类时,就会因为没有准备好 Apache 而失败。
通过在自己的类中放置 Apache 的包资源并使用 include apache
包含它,你就可以解决这个问题, 因为 Puppet 不介意多次包含一个相同的类。但是这有一个缺点,即每个具有潜在冲突的资源都必须有它自己的类。 虚拟资源可以解决这个问题。虚拟资源就像是个普通的资源,特别之处在于它以 @ 字符开始,例如:
@package { "apache2-mpm-worker": ensure => installed }
你可以把它看作是个 “FYI(仅供参考)” 资源:我只是告诉 Puppet 这个资源存在,但不希望用它做任何事情。 Puppet 将会读取并记住虚拟资源定义,但实际上不会创建这个资源,直到你明确指出要创建此资源。
要创建这个资源,使用如下的 realize
函数:
realize( Package["apache2-mpm-worker"] )
对于你想要的资源,可以多次调用 realize
而且不会产生冲突。 因此,虚拟资源用于:当在几个不同的类中都需要相同的资源,且它们可能会在相同的节点上共存的情况。
操作步骤
创建名为
app
的新模块:# mkdir -p /etc/puppet/modules/app/manifests
使用如下内容创建
/etc/puppet/modules/app/manifests/facesquare.pp
文件:class app::facesquare { realize( Package["apache2-mpm-worker"] ) }
使用如下内容创建
/etc/puppet/modules/app/manifests/twitstagram.pp
文件:class app::twitstagram { realize( Package["apache2-mpm-worker"] ) }
使用如下内容创建
/etc/puppet/modules/admin/manifests/virtualpackages.pp
文件:class admin::virtual-packages { @package { "apache2-mpm-worker": ensure => installed } }
在一个节点上包含如下代码:
node cookbook { include admin::virtual-packages include app::facesquare include app::twitstagram }
运行 Puppet。
工作原理
你可以在 admin::virtual-packages
类中定义一个包的虚拟资源。 所有节点都可以包含这个类,并且你可以将所有虚拟资源都放在此类中。 这些虚拟资源都不会实际安装到节点上,直到你调用 realize
:
class admin::virtual-packages { @package { "apache2-mpm-worker": ensure => installed } }
每个需要 Apache 包的类都可以对虚拟资源调用 realize
:
class app::twitstagram { realize( Package["apache2-mpm-worker"] ) }
Puppet 知道如何处理它,因为你设置了相应的虚拟资源,你打算多次引用同一个包, 而不会意外地创建具有相同名子的两个资源。所以,这正确地实现了我们的需求。
更多用法
为了实现(realize)虚拟资源,你也可以使用 collection 语法:
Package <| title = "apache2-mpm-worker" |>
使用这种语法的好处是,你不仅可以指定资源名,而且可以指定 tag,例如:
Package <| tag = "security" |>
或者,你可以指定资源类型的所有实例,在查询部分保留一个空格即可:
Package <| |>
参见本书
本章的 使用虚拟资源管理用户 一节