puppetrun を試すならやっぱ trunk 版の方がよさげ
puppet 今試すなら バージョン 0.22.1 を使え、そして gem で入れるな というエントリを書いたわけですが、puppetrun で特に exec を使って puppet クライアントで何かコマンドを実行させたい、ということであれば、今は trunk 版を使ったほうがいいかも。
理由。まず以下の様な単純なコマンドを実行させる site.pp をつくる。
exec { 'touch':
path => '/bin',
command => 'touch /tmp/puppet',
}
で、puppetmasterd を puppet サーバで起動。
$ sudo puppetmasterd
次に puppet クライアント側で puppetd を起動。
$ sudo puppetd --listen --no-client --server kenny.southpark -v
そして、puppet サーバ側で puppetrun を起動して、設定した exec をクライアントで実行させる。
$ sudo puppetrun --host cartman.southpark
すると、0.22.1 では、クライアント側の puppetd がハングした状態になります。strace で見ると、以下の記述が延々と表示されるという状態に。
rt_sigprocmask(SIG_SETMASK, [], ULL, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], ULL, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], ULL, 8) = 0 rt_sigprocmask(SIG_SETMASK, [], ULL, 8) = 0 ... (以下繰り返し)
0.22.1 と 0.22.2 の間で、lib/puppet/type/exec.rb にかなり修正が入ってるので、おそらく 0.22.2 では大丈夫だろうけど、前エントリ で書いたように、0.22.2 ではそもそも puppetd がエラーで起動できない、という問題がある。なので、trunk 版を使うのがいい、という結論になりました。trunk 版だと問題なく実行できることを確認済み。
ただ、これも 前エントリ で書いたように、puppetrun に以下の一行を追加しないと動かないので注意。 fix された。自分の修正内容と違うけど。
require 'puppet/network/client/runner'
まだ実戦投入はやめておいた方がよさそうかな…。まだ検証段階なのでいいのですが。
puppet 今試すなら バージョン 0.22.1 を使え、そして gem で入れるな
gem がだめなわけは、puppetrun が入らないから。(0.22.1, 0.22.2 で確認。)puppetrun 使わないなら gem で構わないけど。metadata 覗いたら、executables の中に puppetrun がない。こんな感じ。
executables: - puppet - puppetd - puppetmasterd - puppetdoc - puppetca
とりあえずチケットに入れておいた。
あと、最新のバージョン 0.22.2 だと、以下のエラーが出る。
$ sudo puppetd --listen --no-client -v
/usr/lib/ruby/site_ruby/1.8/puppet/util/config.rb:29:in `[]': Undefined configuration parameter 'authconfig' (ArgumentError)
from /usr/lib/ruby/site_ruby/1.8/puppet.rb:83:in `[]'
from /usr/bin/puppetd:360
--listen オプション使うときには、/etc/puppet/namespaceauth.conf が必要で、authconfig にはこのパスがセットされるはずなんだけど、セットされていないためのエラーっぽい。これは trunk では直ってる。
もうひとつ、puppetrun 実行時のエラー。
$ sudo puppetrun --host kenny.southpark
Failed to load ruby LDAP library. LDAP functionality will not be available
/usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/introspection.rb:5:in `parent': private method `split' called for :Client:Symbol (NoMethodError)
from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:463:in `const_missing'
from /usr/local/bin/puppetrun:343
from /usr/local/bin/puppetrun:335:in `fork'
from /usr/local/bin/puppetrun:335
kenny.southpark finished with exit code 1
これは puppetrun に以下の一行を追加すれば直る。
require 'puppet/network/client/runner'
Trac の Wiki を emacs で直接編集
emacs trac-wiki mode なんてものがあったんですね。これは便利。
セットアップや設定方法なんかは上のリンクを参照すれば分かるので省略。
M-x trac-wiki を実行すると、まずはプロジェクト名を聞いてくる。
次に認証のためのユーザ名。
そしてパスワード。
編集する Wiki ページ名を聞いてくる。タブで Trac 上にある Wiki ページ一覧を表示してくれたり、補完してくれたりする。
Wiki ページを開くとこんな感じ。
C-c C-c で Trac に保存。
まあ、Firefox 拡張の It's All Text! 使えば、Trac に限らず任意のエディタで編集できるのですが、ブラウザで開く手間が省けるのはいいですね。Emacs-w3m を利用したプレビュー表示にも対応してたりとか、他にも色々便利な機能があります。詳しくは 開発元サイト 参照。
puppet の実行ファイル
Puppet Executables より。またもや超意訳、というかメモ。
puppet
スタンドアロンなインタプリタ。manifest ファイルを直接読んで、自ホストに適用する。あまり使うことはないと思う。
puppetca
SSLv3 証明書ハンドリングのためのコマンド。この辺参照。
puppetd
puppet クライアント側で実行するデーモン。デフォルトでは、puppet サーバに対して定期的に問い合わせに行くけれど、
$ puppetd --listen --no-client
と実行することで、puppet サーバからキックされるのを待ち受ける状態になる。(サーバは後述の puppetrun を実行してキックする。)
puppetdoc
puppet ソースからドキュメントを抽出するためのツール。これもあまり使わないと思う。
puppetmasterd
puppet サーバ側で起動するデーモン。
puppetrun
puppet クライアントをサーバ側からキックする時に使うコマンド。
$ puppetrun --host hostA --host hostB
という感じで特定のクライアントのみキックできるし、
$ puppetrun --all --parallel 5
とかですべてのクライアントをキックする(ただし同時にキックするのは 5 クライアント)といったことができる。
$ puppetrun --class web
とかで web クラスのクライアントのみキックとかもできる。ただし、--all や --class は、クライアントホストを LDAP で管理している場合のみ。
うちではこれをメインに使うことになりそう。サーバの数が数百台とかあるから、クライアントから定期的にポーリングされる負荷も馬鹿にならないし、いっぺんにファイルとりにこられたりすると、とんでもないことになるので。
puppet の通信の仕組みにちょっと立ち入ってみる
puppet のクライアント/サーバ間通信は https + XMLRPC で、認証は SSLv3 の証明書認証が利用されています。
通常、SSLv3 で証明書認証とかいうと、CA とか、自己署名証明書とか、色々めんどくさかったりしますが、puppet はこの辺りはほとんど自動で処理してくれるので、とても楽です。
例えば、puppet サーバ側では、puppetmasterd をはじめて起動した時に、CA 関連ファイルや自己署名証明書などを、/etc/puppet/ssl 以下に勝手に作ってくれます。
$ ls -R /etc/puppet/ssl /etc/puppet/ssl: ca/ certs/ csr_kenny.southpark.pem private/ private_keys/ public_keys/ /etc/puppet/ssl/ca: ca_crl.pem ca_key.pem inventory.txt requests/ signed/ ca_crt.pem ca_pub.pem private/ serial /etc/puppet/ssl/ca/private: ca.pass /etc/puppet/ssl/ca/requests: /etc/puppet/ssl/ca/signed: kenny.southpark.pem /etc/puppet/ssl/certs: ca.pem kenny.southpark.pem /etc/puppet/ssl/private: /etc/puppet/ssl/private_keys: kenny.southpark.pem /etc/puppet/ssl/public_keys: kenny.southpark.pem
あれ、CA 証明書っぽいものが二つある、と思ったら、ca/ca_crt.pem と certs/ca.pem はまったく同じものでした。
また、CA 証明書とは別に、kenny.southpark.pem というものができていますが、これはおそらく、自身が puppet クライアントになる時に利用するものと思われます。
CA 証明書の中身を覗いてみるとこんな感じ。
$ sudo openssl x509 -text -in /etc/puppet/ssl/ca/ca_crt.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=kenny.southpark
Validity
Not Before: Mar 20 14:29:16 2007 GMT
Not After : Mar 18 14:29:16 2012 GMT
Subject: CN=kenny.southpark
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:ea:83:02:5a:83:08:02:c8:bc:cd:d0:26:07:e7:
44:f7:a0:0e:0f:26:23:82:ba:e4:ed:d7:c8:88:c6:
43:b7:0a:5d:16:39:a2:6a:48:f9:8f:a5:9d:35:2f:
24:1e:ec:38:6b:73:0f:23:17:84:70:7e:08:08:96:
bd:e6:51:53:f2:fe:1d:ec:2f:d0:9a:5b:3d:ea:92:
8a:39:f5:ff:02:ff:6b:e4:d2:ef:9f:d2:c3:d6:35:
d8:5c:51:42:d9:16:59:62:c5:da:9a:9d:cd:f7:91:
a7:06:0b:28:8e:7f:4a:52:bc:5f:c3:5c:cb:b3:e3:
81:d0:1b:ca:b6:7f:73:b2:3f
Exponent: 65537 (0x10001)
X509v3 extensions:
Netscape Comment:
Puppet Ruby/OpenSSL Generated Certificate
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
82:0D:36:AD:29:30:30:2D:CC:2D:EB:EA:F9:32:07:44:80:11:D3:E6
X509v3 Key Usage:
Certificate Sign, CRL Sign
Signature Algorithm: sha1WithRSAEncryption
e0:0b:a7:28:39:8e:09:cc:91:85:ce:13:19:c1:9b:ba:21:c3:
d8:09:c2:ee:93:ac:8d:76:91:18:7a:31:01:fc:55:8b:84:e6:
69:3f:f5:a3:62:ce:cc:af:87:21:42:d4:0d:ab:02:62:26:4f:
c2:f4:a2:22:4f:52:a5:06:bd:88:4c:65:89:9e:98:4c:cb:82:
ce:09:50:e0:4b:67:59:1e:d7:26:75:2f:6f:3d:d3:d4:92:55:
79:06:5e:56:39:2b:15:b0:67:d9:00:79:09:37:86:1a:a1:30:
e0:ce:e8:2b:0a:16:92:73:a3:b8:1f:16:c8:60:f7:7d:c5:24:
09:66
-----BEGIN CERTIFICATE-----
MIICIzCCAYygAwIBAgIBADANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9rZW5u
eS5zb3V0aHBhcmswHhcNMDcwMzIwMTQyOTE2WhcNMTIwMzE4MTQyOTE2WjAaMRgw
FgYDVQQDDA9rZW5ueS5zb3V0aHBhcmswgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
AoGBAOqDAlqDCALIvM3QJgfnRPegDg8mI4K65O3XyIjGQ7cKXRY5ompI+Y+lnTUv
JB7sOGtzDyMXhHB+CAiWveZRU/L+Hewv0JpbPeqSijn1/wL/a+TS75/Sw9Y12FxR
QtkWWWLF2pqdzfeRpwYLKI5/SlK8X8Ncy7PjgdAbyrZ/c7I/AgMBAAGjeTB3MDgG
CWCGSAGG+EIBDQQrFilQdXBwZXQgUnVieS9PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0
aWZpY2F0ZTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSCDTatKTAwLcwt6+r5
MgdEgBHT5jALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEA4AunKDmOCcyR
hc4TGcGbuiHD2AnC7pOsjXaRGHoxAfxVi4TmaT/1o2LOzK+HIULUDasCYiZPwvSi
Ik9SpQa9iExliZ6YTMuCzglQ4EtnWR7XJnUvbz3T1JJVeQZeVjkrFbBn2QB5CTeG
GqEw4M7oKwoWknOjuB8WyGD3fcUkCWY=
-----END CERTIFICATE-----
次にクライアント側ですが、こちらもはじめて puppetd(クライアント側で起動するデーモン)を実行した時に、秘密鍵、公開鍵、CSR を自動的に作成し、サーバに対して CSR への署名を求めることが、起動時のメッセージから読み取れます。
$ sudo /usr/sbin/puppetd --server mizzy.org --test err: No certificate; running with reduced functionality. info: Creating a new SSL key at /var/lib/puppet/ssl/private_keys/cartman.southpark.pem info: Creating a new certificate request for cartman.southpark info: Requesting certificate warning: peer certificate won't be verified in this SSL session notice: Did not receive certificate
サーバ側では、証明書リクエストが来ていることを、次のようなコマンドで確認できます。
$ sudo puppetca --list cartman.southpark
これに署名するには、
$ sudo puppetca --sign cartman.southpark
と実行するだけです。これで puppet クライアント/サーバ間で無事通信できるようになります。
セキュアな通信が割りと簡単に実現できていい感じ。
puppet でファイルが変更されたら指定したコマンドを実行するレシピ
puppet で ファイルの配布 ができたので、次はファイルが変更されたら特定のコマンドを実行、にチャレンジ。これは FAQ にやり方書いてました。
puppet サーバで管理している /etc/httpd/conf.d/ 以下のファイルが変更されたら、puppet クライアント上のファイルを更新して httpd を再起動するレシピはこんな感じ。
class web {
define httpd {
$path = '/etc/httpd/conf.d'
file { $path:
source => 'puppet://mizzy.org/files/etc/httpd/conf.d',
recurse => 'true',
}
exec { 'httpd restart':
command => '/etc/init.d/httpd restart',
subscribe => File[$path],
refreshonly => true
}
}
httpd { 'httpd settings': }
}
node 'www.mizzy.org' {
include web
}
/etc/httpd/cond.d/perl.conf を変更して puppet クライアント上で puppetd --test を実行するとこんな感じに。
$ sudo /usr/sbin/puppetd --server mizzy.org --test
info: Caching configuration at /var/lib/puppet/localconfig.yaml
notice: Starting configuration run
info: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf: Removing old backup of type file
notice: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf/source: source changed '{md5}b78c3e53dd7fef842c99f105e9e4204f' to '{md5}a28770c2cdfc4c23faa2ea41b2e67397'
info: //www.mizzy.org/web/httpd[httpd settings]/file=/etc/httpd/conf.d/perl.conf: Scheduling refresh of exec[httpd restart]
notice: //www.mizzy.org/web/httpd[httpd settings]/exec=/etc/init.d/httpd restart: Triggering 'refresh' from 1 dependencies
notice: Finished configuration run in 7.42 seconds
ファイルが更新されてない場合はこうなる。
$ sudo /usr/sbin/puppetd --server mizzy.org --test info: Caching configuration at /var/lib/puppet/localconfig.yaml notice: Starting configuration run notice: Finished configuration run in 6.80 second
puppet file server 1
puppet サーバ上のファイルをクライアントに配布するには、file server 機能を利用するらしい。というわけで、ドキュメント File Serving Configuration から要点を抜き出してみる。
/etc/puppet/fileserver.conf の設定
[module]
path /path/to/files
allow *.domain.com
deny *.wireless.domain.com
こう設定すると、
/path/to/files/sudoers
というファイルを
puppet://server/module/sudoers
で取得できるようになる。
manifest の設定
"the Puppet language" が記述される設定ファイルを manifest と呼ぶらしい。要は puppet クライアントをどう管理するか、が記述された設定ファイルですね。(上の /etc/puppet/fileserver.conf は manifest ではない。)
puppet file server 上のファイルを配布するには、以下の様な設定を manifest に記述。
# copy a remote file to /etc/sudoers
file { "/etc/sudoers":
mode => 440,
owner => root,
group => root,
source => "puppet://server/module/sudoers"
}
source がポイント。
詳細は File Serving Configuration を参照。
puppet の言語構造
Installation Guide を読めば、とりあえず puppet を動かすことはできるけど、やりたいことをやろうと思ってもすぐにできるわけでもない。というわけで、ドキュメントをちゃんと読んでみることにした。
まずは puppet の設定ファイルで使われている内部言語の理解から、ということで、Language Structures を超意訳してみる。
Types
puppet 設定の基本構成単位。管理されるコンピュータ上のオブジェクト(ファイルとかパッケージとか)を表すもので、あらかじめ用意されたビルトインタイプ以外にも、自ら定義することも可能。
file { "/etc/passwd": owner => root, mode => 644 }
package { apache: install => true }
詳しくは Type Reference を参照。
Assignment
変数が利用できる。
$variable = value
$x = foo $y = bar $z = "$x$y"
Bringing Config files together
設定ファイルに、別の設定ファイルをインポートできる。
import "filename"
正規表現も利用可能。
import "classes/*" import "packages/[a-z]*"
Scope
{ } によってスコープが形成される。
変数は一度割り当てられると、同一スコープ内では変更できないが、サブスコープ内では同一名の変数を割り当てることができる。
$var = value
# override $var
define testing {
$var = othervalue
}
Components
ここでいう Components とは、自分で定義する Type のことっぽい。Components の定義と利用は以下の様な感じ。
define svnserve($source, $path, $user = false, $password = false) {
file { $path:
create => directory,
owner => root,
group => root
}
$svncmd = $user ? {
false => "/usr/bin/svn co --non-interactive $source/$name .",
default => "/usr/bin/svn co --non-interactive --username $user --password '$password' $source/$name ."
}
exec { $svncmd:
cwd => $path,
require => file[$path],
creates => "$path/.svn"
}
}
svnserve { dist:
source => "https://reductivelabs.com/svn",
path => "/dist",
user => "puppet",
password => "password"
}
svnserve { "dist/config/apps/puppet":
source => "https://reductivelabs.com/svn",
path => "/etc/puppet",
user => "puppet",
password => "password"
}
利用する時はビルトインタイプと構文上の違いはない。
Server Classes
Class を定義してインクルードすることができる。
class[inherits ] { ... }
継承も可能。
# really simple example
class solaris {
file {
"/etc/passwd": owner => root, group => root, mode => 644;
"/etc/shadow": owner => root, group => root, mode => 440
}
}
class solworkstation inherits solaris {
file {
"/etc/sudoers": owner => root, group => root, mode => 440;
"/bin/sudo": owner => root, group => root, mode => 4111
}
}
include solworkstation
以下の例だと、$operatingsystem の値と同名の Class と、$hostname に応じた Class がインクルードされる。
include $operatingsystem, $hostname ? {
myhost => classA, default => classB
}
$operatingsystem とか $hostname とかは、Facterというライブラリを使ってプリセットされているみたい。
Classes vs. Components
Classes と Components の違いは以下の通り。
- Classes はシングルトンなので、ホスト上でひとつしかないものを定義するのに利用する(OSの種類とか、特定のパッケージとかサービスとか。)
- Components はホスト上で複数あるオブジェクト(バーチャルホストなど)を定義するのに利用する。
あと、Classes は引数を受け取れない、という違いもある。
Subclssing
Class は継承ができる。
class unix {
file { "/etc/sudoers":
owner => root,
group => root,
mode => 440
}
}
class bsd inherits unix {
File["/etc/sudoers"] {
group => wheel
}
}
Using Classes Outside of Puppet
puppet サーバで設定された Class 名が、puppet クライアントの /etc/puppet/classes.txt に保存されるので、それを外部プログラムなどから読み込んで利用したりできるよ、とうことらしい。
FC4 で yum insall した puppet の場合は、/var/lib/puppet/classes.txt に保存されていた。
Nodes
node{ ... }
特定のホストに適用する設定を割り当てる。
以下の例だと、file type はすべてのホストに割り当てられるけど、webserver class と dbserver class の中に書かれた設定は、それぞれ特定のホストにのみ割り当てられる。
class webserver { ... }
class dbserver { ... }
file { "/etc/sudoers": mode => 440 } # apply to everyone
node host1, host2 {
include webserver
}
node host3, host4 {
include dbserver
}
node は継承することも可能。
node base {
include $operatingsystem
}
node kirby inherits base {
include webserver
}
FQDN で指定する時は、シングルクォートで囲む。
node 'host.domain.com' {
...
}
Conditionals
条件指定が可能。
以下の例は $os が何かによって、 $owner に入る値が変わる。
define testing(os) {
$owner = $os ? {
sunos => adm,
redhat => bin,
default => root
}
file { "/some/file": owner => $owner }
}
以下の例は $operatingsystem が何かによって、適用する class が変わる。
case $operatingsystem {
sunos: { solaris {} } # apply the solaris class
redhat: { redhat {} } # apply the redhat class
default: { generic {} } # apply the generic class
}
Reserved words
true, define, inherits, class は予約語。
Comments
sh スタイルのコメントが利用可。
puppet の node 設定ではまる
- http://reductivelabs.com/trac/puppet/wiki/InstallationGuide
- http://reductivelabs.com/trac/puppet/wiki/TestingGuide
- http://people.redhat.com/dlutter/puppet-app.html
といったあたりを読みながら puppet を試していたのですが、node の設定ではまったのでメモ。
pueppt では、
node nag.example.com {
include yum-rawhide
include horde-db-pg
include horde-nag
}
といった設定でターゲットとなるホストと、そのホストでどのようなタスクを実行するかを定義できるのですが、これで puppetmasterd を実行すると、
Syntax error at '.' at /etc/puppet/manifests/site.pp:5
と怒られます。そこで、
node 'nag.example.com' {
include yum-rawhide
include horde-db-pg
include horde-nag
}
とクォートしてあげると OK でした。最初に挙げた URL にあるチュートリアルの例ではクォートされておらず、そのままやるとはまりますのでご注意を。
追記
Language Structures を読んだら、「You can specify fully-qualified node names, but you have to single-quote the names:」ってちゃんと書いてあった。
Older posts: 1 2