puppet 模块结构

01 Dec 2015 . . Comments #puppet

我们公司的配置管理用的是 puppet,从 2.7 版本开始,一直用到现在,积累了一百多个 puppet 模块。由于模块的作者不同,写出来质量也良莠不齐,在迁移到 AWS 的过程我们发现需要一个良好的模块写作风格,保证 Puppet 模块的易维护性。

这篇文章简单的讲解了 puppet 模块的结构,以及编写模块的最佳实践,我读了之后发现很有用,在这里基于我们的使用心得,简单的总结一下。

##基本原则

  • 一个模块必须只有一个入口,这个入口提供模块的基本用法。
  • 模块配置应该用同一的方式在一个地方进行
  • 模块应该由多个有不同作用的小class组成,class提供相关细节。
  • 对于最常见的用法,用户不应该需要知道所有的 resource 名字
  • 对于最常见的用法,用户不需要提供任何参数,使用默认值就足够。

模块结构

一般来说,Puppet 模块主要做三件事情

  • 安装软件包
  • 管理配置文件
  • 启动服务

对应 Puppet 模块可以分为这三个不同作用的类:

  • install.pp 负责服务软件包的安装
  • config.pp 负责配置管理
  • service.pp 负责管理服务的启动和关闭

同时我们需要一个模块的入口: 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

Class 内容

对于不同的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 一样,这篇文章只是其中一小部分。