ProPuppet00

#!html

[wiki:ManagingInfrastructureWithPuppet Managing Infrastructure With Puppet] の中でも少しだけ触れた、Pro Puppet についてメモ。

こちらは内容盛りだくさんで、Puppet をヘビーに使っている人でも読みごたえがあるんじゃないかと。たとえば、バージョン違いの Puppet を混在させる方法、といったところもフォローされていたり。

ただし、Puppet や、Git といった周辺ツールのインストール方法まで詳細に書かれていて、この辺は自分には必要ないなー、と思ったりもした。

とはいえ、最近の Puppet 動向を追いかけていない自分には、とても有意義な内容が多かったので、その辺についてメモしてみる。

(あんまり書きすぎると出版社の人に怒られそうなんで、さらっと。あと、量が多くなりそうなので、何度かにわけて書く。)


モジュール化について

Puppet 解説書なんで、当然のことながらマニフェストの書き方が最初の方に出てくるんだけど、本書ではいきなりモジュールを作成するところから始めていて驚いた。

このことで思ったのは、マニフェストはとにかく全部モジュール化しちゃう、というのがベストプラクティスなのかもしれない、ということ。

第8回 Puppet実践テクニック(その3) の中で書いているデータファイルの構造は、modules ディレクトリはあるものの、すべてをモジュール化することは想定していないため、menifests ディレクトリの下に、クラス毎にマニフェストファイルを置いている。

このやり方だと、dist の下にもクラス毎にスタティックなファイルがあったり、templates の下にもクラス毎にテンプレートがあったりで、同じクラスで利用するマニフェスト、スタティックファイル、テンプレートがばらばらな場所にあって、非常にさがしづらい、といったはめになる。(なので上の記事の内容は今となっては真似しない方がいい。)

これがすべてモジュール化されていると、

modules/
  |
  +--- ssh/
  |     |
  |     +--- files/
  |     |
  |     +--- manifets/
  |     |
  |     +--- templates/
  |
  +--- postfix/
        |
        +--- files/
        |
        +--- manifests/
        |
        +--- templates/

といった形で、関連するマニフェスト、スタティックファイル、テンプレートが1カ所にまとまっていて、非常に見通しが良い。


モジュールのマニフェストファイルとクラスの分け方

本書では以下のようにマニフェストファイルをわけている。(ssh モジュールの例。ファイル内容は本とは少し変えてる。)

ssh/
 |
 +--- manifets/
        |
        +--- init.pp
        |
        +--- params.pp
        |
        +--- install.pp
        |
        +--- config.pp
        |
        +--- service.pp

で、各ファイルの内容は以下のような感じ。

init.pp

ssh モジュールを利用をするために include ssh すると、このファイルが読み込まれ ssh モジュールが適用される。

このファイルでは、さらにモジュール内で細分化されたクラスを include しているだけ。

class ssh {
    include ssh::params, ssh::install, ssh::config, ssh::service
}

環境毎に異なるパラメータをまとめるためのファイル。このファイル内にパラメータをまとめることによって、モジュール全体の見通しを良くする。

class ssh::params {
    case $operatingsystem {
        Solaris: {
            $package_name = 'openssh'
            $service_name = 'sshd'
        }
        ...
    }
}

install.pp

必要なパッケージをインストールするためのマニフェスト。

class ssh::install {
    package { $ssh::params::package_name: ensure => installed }
}

config.pp

設定ファイル用マニフェスト。

class ssh::config {
    file { '/etc/ssh/sshd_config':
        ensure  => present,
        source  => 'puppet:///modules/ssh/sshd_config',
        require => Class['ssh::install'],
        notify  => Class['ssh::service'],
    }
}

service.pp

サービス用マニフェスト。

class ssh::service {
    ensure  => running,
    enable  => true,
    require => Class['ssh::config'],
}

こういった形で、ssh モジュールの中でも、ssh::params, ssh::install, ssh::config, ssh::service といった形でクラスを役割毎に細分化して、ファイルもクラス毎に作成、といった形で、一ファイル内の見通しを良くする、というやり方が紹介されている。

もうひとつのポイントは、require や notify で Class 指定していること。(Class を require とかするのって以前のバージョンからできるんだっけ?)

たとえば、sercice.pp では、

require => Class['ssh::config'],

といった指定があるが、これは以下のように、Class ではなく File でも指定できる。

require => File['/etc/ssh/sshd_config'],

ひとつの設定ファイルから構成されているようなモジュールであればこれでも良いが、複数の設定ファイルから構成されるようなモジュールだと、変更に対して脆くなってしまう。例えば postfix モジュールで考えてみる。

最初は main.cf のみ Puppet で管理して、他の設定ファイルはデフォルトのまま、という状態を想定すると、マニフェストは以下のようになる。

class postfix::config {
    file { '/etc/postfix/main.cf':
        source => 'file:///modules/postfix/main.cf',
    }
}

class postfix::service {
    service { 'postfix':
        ensure  => running,
        enable  => true,
        require => File['/etc/postfix/main.cf'],
    }
}

後から、master.cf もデフォルトのままではなくなったので、Puppet で管理することにすると、マニフェストは以下のように、postfix::config と postfix::service の両方を書き換えることになる。

#!diff
diff --git a/postfix.pp b/postfix.pp
index f55234e..a032d65 100644
--- a/postfix.pp
+++ b/postfix.pp
@@ -2,12 +2,16 @@ class postfix::config {
     file { '/etc/postfix/main.cf':
         source => 'file:///modules/postfix/main.cf',
     }
+    file { '/etc/postfix/master.cf':
+        source => 'file:///modules/postfix/master.cf',
+    }
 }

 class postfix::service {
     service { 'postfix':
         ensure  => running,
         enable  => true,
-        require => File['/etc/postfix/main.cf'],
+        require => [ File['/etc/postfix/main.cf'], File['/etc/postfix/master.cf
     }
 }

もし、Class を require するようになっていれば、main.cf だけを管理する最初の状態では、マニフェストは

class postfix::config {
    file { '/etc/postfix/main.cf':
        source => 'file:///modules/postfix/main.cf',
    }
}

class postfix::service {
    service { 'postfix':
        ensure  => running,
        enable  => true,
        require => Class['postfix::config'],
    }
}

となっており、master.cf を追加した場合、差分は

#!diff
diff --git a/postfix.pp b/postfix.pp
index 9745478..e82621c 100644
--- a/postfix.pp
+++ b/postfix.pp
@@ -2,6 +2,9 @@ class postfix::config {
     file { '/etc/postfix/main.cf':
         source => 'file:///modules/postfix/main.cf',
     }
+    file { '/etc/postfix/master.cf':
+        source => 'file:///modules/postfix/master.cf',
+    }
 }

 class postfix::service {

だけになり、postfix::service はまったく変更する必要がない。