書いた人:諸富 洋 (@164c)
前回の「Chef でサーバ管理を楽チンにしよう! (第 1 回)」では、Chef の紹介とカンタンなレシピの書き方とテストの方法を紹介しました。今回は次の一歩を紹介したいと思います。
ひとたび Chef を導入したならば、その後はレシピを書くことが Chef に関わるタスクの大半になります。ですので、今回も引き続き、レシピの書き方についてお伝えしていきます。今回のテーマは「○○したら、それを受けて××する」という手続きのレシピの書き方です。
Chef を導入したばかりでレシピの書き方に迷っている人
前回では、ミドルウェアなどの設定ファイルの管理を想定した「一定の内容が書かれたファイルを指定の場所に指定の状態に保つ」ことを実現しました。
さて、この設定ファイルの内容を変える必要が出てきたとします。ただテキストを変更するだけなら、とてもカンタンです。テンプレートを修正して chef-solo を実行するか、chef-client の実行をすれば変更後の内容に置き換わります。
ところが、大抵のミドルウェアでは設定ファイルの内容を置き換えるだけでは変更内容は反映されません。だいたい後の処理として再起動など (reload とか restart) が必要になります。 このような「○○したら、それを受けて××する」というのはレシピを書く上での超頻出パターンです。
今回はこの「○○したら、それを受けて××する」について挑戦してみたいと思います。Chef Wiki の Resources のページを参考にしながら進めます
また、前回の続きということで、cookbook “test” がすでにある状態から始めます。
「httpd.conf を修正したら apache 再起動」をイメージしてみます。 これは前述の参考サイトにほとんどそのまんま書いてあります。
# test/recipes/default.rb
template "/tmp/test.conf" do
notifies :restart, "service[httpd]"
end
service "httpd"
これだけです。Service リソースは引数と同名の init スクリプトを探して実行します。service コマンドと同じですね1。
http://wiki.opscode.com/display/chef/Resources#Resources-Service
設定ファイルに変更がないときのログ
“content has not changed.” で “Processing service[httpd] action nothing” とでています。実際の動作も何もしません。
設定ファイルに変更があった時のログ
“Processing template[/tmp/test.conf] action create” ということでファイルが置き換えられます。 その後 “sending restart action to service[httpd] (delayed)” ということで httpd に対して restart が送られます。 最後に (delayed) というのがあります。
変更時に処理を指定する際に “notifies” を使いますが、notifies のデフォルトは delayed となり、キューに貯められて Chef の処理の最後にまとめて実行されます。 今回は、処理がひとつしかないので特に困りませんが、依存関係のある複数の処理が走る場合に、即時実行したい場合は、:immediately を指定しましょう。
# test/recipes/default.rb
template "/tmp/test.conf" do
notifies :restart, "service[httpd]", :immediately
end
service "httpd"
これで実行してログを確認すると、先程 (delayed) になっていた部分が (immediate) に変わっているはずです。
先ほどの Service リソースのマニュアルに書いてあるとおり、service 名は別名で指定できますし、start、stop、restart などの処理に対してコマンドを明示することもできます。
つまり、
# test/recipes/default.rb
template "/tmp/test.conf" do
owner "root"
group "root"
mode "0644"
notifies :restart, "service[hoge]"
end
service "hoge" do
service_name "httpd"
restart_command "service httpd restart"
end
こう書くことができます。
こういった具合に DSL を使ってやりたいことがカンタンに書けちゃいますので、柔軟に実現することができます。
Service リソースは service の制御しかできません (十分有用ですけど) 。
さらに自由度が高いリソースとして Execute リソースがあります。これを使って、メールを送ってみることにしましょう。
この流れなので「設定ファイルに変更があったら、メール送信」ということにしたいと思います。
# test/recipes/default.rb
execute "sendmail" do
command 'echo "Cook me something tasty." | mail -s "Hello! Chef!" 164c@example.com'
end
template "/tmp/test.conf" do
owner "root"
group "root"
mode "0644"
# notifies :restart, "service[hoge]"
notifies :run, resources(:execute => "sendmail")
end
こんな感じに書いてみます。execute のブロックは呼び出す前に記述しておく必要があります。
これを実行するとメールが送られてくると思います2。ところが、これだとファイルに変更がなくても実行されてしまい、メールが送られてきます。
Execute リソースのアクションは run と nothing で、デフォルトが run になっているためです。ファイルが変更されたときだけ、実行させるためには nothing にしておきます。
# test/recipes/default.rb
execute "sendmail" do
command 'echo "Cook me something tasty." | mail -s "Hello! Chef!" morotomi@328w.co.jp'
action :nothing
end
template "/tmp/test.conf" do
owner "root"
group "root"
mode "0644"
# notifies :restart, "service[hoge]"
notifies :run, resources(:execute => "sendmail")
end
これで完成です。実行してログとメールを確認してみてください。
ちなみに Script リソースを使えばこれと同じようなことは Perl や Python、Ruby などの言語で書くこともできます。
http://wiki.opscode.com/display/chef/Resources#Resources-Script
ところで、マニュアルによると「Execute や Script リソースは “idempotent” を保証してないよ! だからあなたが “idempotent” になるように記載するよう注意してね!」ということが書かれています。”idempotent” とは、何回行なっても同じ結果が得られることを指す概念だそうです3。今回はなんでもできる度をアピールするためこういった例を出しましたが、Chef はサーバ環境などを “idempotent” に保つために設計されたものであり、その思想から外れるものは別のツールに頼るのが後の幸せを買うことになるのかもしれません。
というわけで、今回は以上です。
いきなりですが、ミツバチワークスではプログラマーやインフラエンジニアなど、Web サービスの開発・運用メンバーを募集しています。みんな大好き Rails を使ったプロジェクトも近々開始されます (というかこれが公開されるころには開始されているはず。。) Chef以外にも様々な取り組みを行なっていますので、興味があるかたはぜひ、「仲間募集のお知らせ」をご覧ください!
諸富 洋。モバイル向けブログサイト「DECOLOG」を運営するミツバチワークス株式会社の中の人。@164c。DECOLOG TECH BLOG。