我们公司的配置管理用的是 puppet,从 2.7 版本开始,一直用到现在,积累了一百多个 puppet 模块。由于模块的作者不同,写出来质量也良莠不齐,在迁移到 AWS 的过程我们发现需要一个良好的模块写作风格,保证 Puppet 模块的易维护性。
这篇文章简单的讲解了 puppet 模块的结构,以及编写模块的最佳实践,我读了之后发现很有用,在这里基于我们的使用心得,简单的总结一下。
##基本原则
class
组成,class
提供相关细节。一般来说,Puppet 模块主要做三件事情
对应 Puppet 模块可以分为这三个不同作用的类:
同时我们需要一个模块的入口: init.pp
,这样我们有了四个 pp 文件。除此之外,对于复杂的模块,一般还会有一个 params.pp,用来通过模块的一些默认值。这样就有了5个基本的 class,以下是我们一个模块的 manifests 目录。
[woosley.xu@myhosts manifests]$ ls -l
总用量 32
drwxr-xr-x 2 woosley.xu liveops 4096 7月 15 05:56 config
-rw-r--r-- 1 woosley.xu liveops 1045 6月 19 06:48 config.pp
-rw-r--r-- 1 woosley.xu liveops 498 7月 8 01:52 init.pp
-rw-r--r-- 1 woosley.xu liveops 437 11月 24 03:04 install.pp
-rw-r--r-- 1 woosley.xu liveops 584 6月 19 06:48 instance.pp
-rw-r--r-- 1 woosley.xu liveops 4793 6月 19 06:48 params.pp
-rw-r--r-- 1 woosley.xu liveops 127 6月 19 06:48 service.pp
[woosley.xu@myhost manifests]$
可以看到这个目录里面还有一个 config 目录,这是由于这个模块比较复杂,需要配置的地方较多,于是将 config 又拆分成了更小的 pp 文件。
[woosley.xu@myhost config]$ ll
总用量 12
-rw-r--r-- 1 woosley.xu liveops 481 6月 19 06:48 service.pp
-rw-r--r-- 1 woosley.xu liveops 1178 7月 15 05:56 ssh.pp
-rw-r--r-- 1 woosley.xu liveops 3540 6月 19 06:48 theconsortium.pp
对于不同的pp文件,根据具体的使用目的不同,其内容也很明确。
install.pp
包含的是安装软件包的语句,比如
class ntp::install {
package{'ntpd':
ensure => installed,
}
}
config.pp
包含的是配置相关内容,比如
class ntp::config {
File{
owner => root,
group => root,
mode => 644,
}
file{'/etc/ntp.conf':
content => template('ntp/ntp.conf.erb');
'/etc/ntp/step-tickers':
content => template('ntp/step-tickers.erb');
}
}
service.pp
包含的是保证服务运行的相关内容,比如
class ntp::service {
service{"ntp":
ensure => $ntp::ensure,
enable => true,
}
}
params.pp
一般包含模块所需要的参数,比如
class ntp::params {
$ensure = $::ntp_ensure ?{
undef => "running",
default => $::ntp_ensure,
}
}
这里设置的参数一般是作为 enc 里面的 Parameters 传递进来的,和传递给类的 class parameters 有一定区别,关于如何使用 params.pp,puppet 官方也有相关文档,见此
init.pp 负责将整个模块的逻辑串起来。
class ntp() inherits ntp::params {
class{"ntp::install":} ->
class{"ntp::config": } ~>
class{"ntp::service} ->
Class["ntp"]
}
使用 -> 和 ~> 来表达依赖关系是个人觉得比较推荐的做法,这样可以使模块的整个逻辑看起来比较清晰。
总的来说,puppet 本身作为一个 DSL 语言,强大但相对复杂,写好它需要用到像编程语言中有的 best practice 一样,这篇文章只是其中一小部分。