Everyday Deadlock

by hayamiz.com

入門Chef Solo 読んでる

2013/03/19
入門Chef Solo - Infrastructure as Code
伊藤直也 (2013-03-11)
売り上げランキング: 16

自動構成管理ツールChef(のスタンドアロン版であるChef Solo)の入門本である「入門Chef Solo - Infrastructure as Code」を読み始めました。

サーバ管理を1台でもやっていて、自動構成管理をしたことがない人は、間違いなく読む価値があります。

サーバの自動構成管理は、たった1台のサーバを管理するだけでも大いにやる価値があります。 もしも色々と手を加えてたくさんのサービスを動かしているサーバが壊れて、1から再構築しなおさなければならないときに、 前の状態まで間違いなく戻せる自信がありますか?僕はないです。 また、Chefのようにコードの形で構成情報を記述できるということは、 それをバージョン管理することでサーバの構成情報を時系列にトレースすることも可能となります。

自分のメールサーバを運用しているVPSとか、研究室の自分用ルータ兼CIサーバ兼gitレポジトリ用のマシンとか、 適当なシェルスクリプトと作業日誌でなんとかお茶を濁してきたのですが、 そろそろもっとスマートな方法で管理したいと思っていたところに、 ちょうどいい本が出てきたので早速買って読んでみました。 大体半分くらいは読み終わりました。

Chefというソフトウェアは、サーバの設定を一元管理するためにいろいろな概念を導入しているので、 いきなり全部を理解しようと思うとおそらく挫折してしまいます。 この本は、Chefを使い始める上で最初にどこからとりかかればよいのか、 とても丁寧に解説されていてまさに「入門」にうってつけです。

気になった点

代表的なレシピのサンプルとして chef-td-agent が紹介されていますが、 この中で参照している ohai の node['lsb']['codename'] はこのような使い方をするべきではないと思います。

(...)
case node['platform']
when "ubuntu"
  dist = node['lsb']['codename']
  (...)
  apt_repository "treasure-data" do
    uri source
    distribution dist
    (...)
  end
  (...)

chef-td-agentの例では上のようなコードでLinuxのディストロ名を取得して、それを元に td-agent の apt-line を構成します。 ここで、lsb_releaseコマンド(lsb-releaseパッケージ)がインストールされていない場合には、 ohaiはcodenameを取得できず、distの値はnilになってしまいます。 結果として不正な apt-line が生成されて、td-agentパッケージのインストールは失敗します。

lsb_releaseがないなら、packageリソースで事前にインストールして ohai を reload すればええやん、 と思うのですが、実はこれでもうまくいきません。

package "lsb-release" do
  action :install
end

ohai "reload" do
  action :reload
end

(...)
case node['platform']
when "ubuntu"
  dist = node['lsb']['codename']
  (...)
  apt_repository "treasure-data" do
    uri source
    distribution dist
    (...)
  end
  (...)

コードで書くとこんな感じでしょうか。 見た目的には、上から逐次リソースの記述が評価されていけば、 dist = にたどり着くときには ohai がリロードされて node['lsb']['codename'] に正しい値が設定されていそうに見えます。

しかし実際には、Chefのレシピは実行される前に一旦コンパイルされ、node['lsb']['codename']はコンパイル時点の値に固定化されます。 そのため、上のようなレシピを書いても、lsb_releaseが存在しない状態で作成されたohaiのnodeが参照され、distの値はnilになり、 誤ったapt-lineが登録されてしまうため実行に失敗します。 ただし、2回目に実行したときにはlsb_releaseコマンドが存在するので、 コンパイル時点でohaiはnode['lsb']['codename']を正しく検出でき、今度は成功します。

そういうわけで、場合によっては1回目が失敗して2回目が成功するという、少しいやらしいレシピが出来上がってしまいます。裸のdebian squeezeではlsb_releaseがないので、まさにこの問題ではまりました。 そういう意味で、キーサーバからキーを勝手に取得する等々便利な側面もありますが、aptクックブックのapt_repositoryはちょっと使いどころに困る代物です。

では、どうすればlsb_releaseがインストールされていない状態から1発で成功するレシピを書くことができるか? ベストな方法かどうかわかりませんが、templateリソースを使うことでとりあえずの問題は解決できます。 templateリソースで指定したテンプレートファイル中でのohaiの値はファイル生成時点で逐一評価されるため、ohaiのリロードが効きます。 あとは、ruby_blockリソースもohaiの値を実行時に評価できるので、コマンド実行とかはこちらに任せてしまえそうです。

余談

レシピのコンパイルというのは、実際のところレシピであるRubyプログラムが全て評価されて、Chefの内部的な実行プランみたいなものを生成して、 その生成されたプランが実行されることで初めてレシピに記述された処理が走るという仕組みになっているのだと思います。 イメージとしては、Lispのマクロ展開とコード実行に近い感じでしょうか。

レシピを実行する仮定でシステムの状態が更新されてゆき、それをohaiをリロードしながら拾って追随する、 というパターンの処理は、この評価の仕組みを理解していないときちんと記述するのは難しいです。

category: diary
tags: book and chef
このエントリーをはてなブックマークに追加

この記事にコメントする

comments powered by Disqus


このエントリーをはてなブックマークに追加