Opscode 社 Chef ハンズオン・トレーニング

ブログを書くのが遅れてしまったのですが、10/5(金) 10:00〜17:00 に「Opscode 社 Chef ハンズオン・トレーニング」というものに参加してきました。
Opscode 社員である Sean OMeara 氏から Chef の中級的な使い方を教えてもらうというもので、非常に内容が濃く充実した時間を過ごすことができました。

内容については jedipunkz さん・tkak さんがかなり詳しく書いてくださっているので (ありがとうございます!)、この記事には個人的におもしろかったところや感想を書いておきます。

参考:

構成管理の歴史

Sean 氏曰く、従来型の構成管理では下に挙げる 4 つのアプローチが採用されてきました。

  • 手動で設定を行う (Manual Configuration)
  • スクリプトを書く (Scripting)
  • ファイル配布 (File Distribution)
    • NFS mounts, rdist, scp-on-a-for-loop, rsync on cron
  • 実行管理 (Execution Management)
    • Cluster SSH、Golden Images、ISConf

スクリプトを書く (Scripting)

上記はいずれも欠点を抱えており、「手動で実行する」というのはサーバが増えれば増えるほど非効率になるためもちろん論外ですが、一見筋の良さそうな「スクリプトを書く」というアプローチにも不便なところがあります。

Sean 氏は "not safe to run twice" (2 回実行したときに安全ではない) と表現されていましたが、このことについて自分の言葉で少し説明してみます。

そもそも「環境構築のためにスクリプトを書く」とき、ほとんどのケースでは「まっさらなサーバ」に対して「1 度だけ実行する」こと、つまり「初期構築」専用であることが前提となっているように思います。

これは当然のようですが、実は効率が悪い面もあります。なぜなら「環境」というのは 1 度作ったあとで要件が変わり、変更を施す必要がかならずと言っていいほど出てくるからです。

こんなとき「スクリプトを書く」アプローチでは、下記のどれかで対処するかと思います。

  • 仕方ないから新しい変更点だけは手動で適用してしまう
  • 新しい変更点を手動で適用し、古くなったスクリプトの末尾にも書き加えておく
  • 新しい変更点を加える 2 つめのスクリプトを作成して実行する
  • 古いスクリプトで実行した結果を全て切り戻した上で、修正したスクリプトを実行する
  • サーバを一度初期化し、修正したスクリプトを実行する

どれもイマイチだし、そもそも「一度作成したスクリプトをどう保守していくか」という運用指針を考えるのがすごく面倒くさいです。
(あとサーバの運用がすでに開始されている場合には、4・5 番目は使えなかったり。)

これに対して Chef がサーバに設定を反映する過程は "convergence" (収束、あるべき状態に持っていく) と呼ばれており、「レシピ」は「初期構築」専用ではなく何度も実行することを前提としています。

たとえばレシピでは「ファイルへの書き込み」をこのように記述することができますが、

file "/tmp/file1" do
 content "hi there!\n"
end

これは「初期構築時に 1 回だけファイルを書き込む」ことを意味しているわけではありません。実際の挙動は下記のようになります。

  • もし /tmp/file1 が存在しない場合
    • /tmp/file1 を作成し、"hi there!\n" という文字列を書き込む
  • もし /tmp/file2 が存在する場合
    • 内容が "hi there!\n" だった場合
      • なにもしない
    • 内容が "hi there!\n" ではなかった場合
      • /tmp/file2 を上書きし、"hi there!\n" という文字列を書き込む

このように比較してみると Chef が「2 度実行しても安全」なのがよく分かると思います。
この仕組みなら 1 つのレシピを、初期構築だけでなく運用時のどの場面でも差分適用のために利用できます。

(もちろん、スクリプトでも「ファイルが存在しない場合にだけ書き込む」といった convergence を実装することはできますが、それはすなわち独自で Chef を実装するようなものなので、最初から Chef を使っておいたほうが効率がよいです。)

ファイル配布 (File Distribution)

次に、これもよく使われているように思うのですが、NFS / rsync 等の方法で複数のサーバへディレクトリ構造ごとファイルを同期する「ファイル配布」という方法があります。
Sean 氏は「スクリプトを書くよりはマシだけど『Apache を再起動する』とかサービス管理は行えない」と言っていました。
まさにその通りで、静的にディレクトリ構造を同期するだけなので、サーバの内部で行わなければならない「サービス起動」「シンボリックリンク張り替え」「Cron 登録」等は行うことができません。別途 capistrano 等の他の仕組みと組み合わせるのがメジャーでしょうか。

実行管理 (Execution Management)

Sean 氏によると今いちばん普及しているのが「実行管理」という手法らしいです。
勉強不足で「実行管理」というのがどういうくくりなのかいまいちピンとこなかったのですが、例としては "Cluster SSH、Golden Images、ISConf" が挙げられていました。

このうち "Cluster SSH" というのは capistrano や tomahawk 等、複数サーバへ SSH 経由でコマンド実行する仕組みのことを指しているのだと思います。Sean 氏は「サーバの台数が極端に増えたときにスケールしない」というようなことを言っていたように思います (うろ覚え)。

Golden Images というのはあとから調べて分かったのですが、設定済みのサーバを再利用可能なイメージの形で保存しておき、使い回す手法のようです (クラウドが主流になってからは非常によく使われている手法だと思います。)

「分かりやすい」「すぐにサーバを作れる」「どんな OS でも使える」のがメリットですが、下記のようなデメリットもあります。

  • Web サーバ/DB サーバ/DNS サーバ等、サーバの種類に応じて多数のイメージを管理する必要がある
  • イメージに対して加えた変更の履歴が管理できない
  • イメージに対して加えた変更を、運用中のサーバに加える際にはリブートが必要になる

参考:

説明してきた通り、構成管理には本当にさまざまなやり方があり、そしてそのどれもが「なんかイマイチ」だったのですが、そういう欠点を考慮した上で解決策 (pull 型アーキテクチャや convergence) を提示しようとしてきたのが CFEngine/Puppet/Chef の流れだったんだろうな、というのをしみじみと感じました。

shef の使い方

shef というツールがあるのは知っていたけど、どういう風に使うのかあまり具体的な例を見れてよかったです。
下記が実際に Sean 氏が打っていたコマンド。人に Chef がどんなものかを説明する際にも使えそうに思いました。

[root@localhost ~]# shef --solo
chef > attributes
chef:attributes > default['foo']['bar']='baz'
chef:attributes > ^D
chef > node['foo']['bar']
chef > recipe
chef:recipe > file "/tmp/file1" do
chef:recipe >   content "hi there!\n"
chef:recipe ?> end
chef:recipe > file "/tmp/file2" do
chef:recipe >   content "hi there again!\n"
chef:recipe ?> end
chef:recipe > file "/tmp/file3" do
chef:recipe >   content "blah\n"
chef:recipe ?> end
chef:recipe > run_chef

chef:recipe > # C-z で抜けて /tmp/file1 を消したり /tmp/file2 の内容を書き換えたりして、
chef:recipe > # fg で戻り run_chef を実行し「同じ状態」に保ってくれることを確かめていた。

chef:recipe > resources # 誰かが質問していたリソースの一覧を見るコマンド

Tab キーでメソッドの補完をしてくれるのも便利そうでした (これは irb 自体の機能か…)。

chef > node.na[Tabキー]
node.name            node.name=           node.name_type       node.named_captures  node.names           node.nan?          
node.native

その他雑多なメモ

  • 環境 (environment) について
    • 検索時に環境で絞り込む haproxy cookbook の例 (solr のクエリに "AND chef_environment:#{node.chef_environment}")
    • 環境は cookbook のバージョンを管理するために使える
    • タグ (tag) はあまり使われていないっぽい (環境のように cookbook のバージョン管理もできない)
  • why-run について
  • Chef は基本的に pull だが push したいときにどうするのか?
    • 99% は Chef、最後の 1% は capistrano や fabric に任せる (スケールしない)
    • 手動で chef を実行する
    • data_bags を使って chef 実行のタイミングを制御する

まとめ

とりとめのないメモになってしまいましたが、Chef を開発している Opscode 社の社員が Chef をどんな風に使いこなしているのかを実演してもらえたのがすごく良かったです。
また機会があればぜひ参加したいと思いました。英語が話せなくて質問ができなかったので、今度はがんばって英語で質問したりしたい。
最後になりましたが、主催者の皆様、お誘いありがとうございました&お疲れ様でした。