インフラの現場で、Chefを「ただの自動化ツール」として使っているうちは、まだ序の口です。本当のプロは、Chefが持つ「収束(Convergence)」という哲学を深く理解し、無駄な処理を徹底的に排除した「極めて美しいコード」を書きます。
今日は、Chefにおける「条件分岐の極意」である `only_if` と `not_if` を深掘りします。これをマスターすれば、あなたの書くレシピは数秒で完了し、サーバーの負荷も最小限に抑えられるようになります。
—
1. そもそも「なぜ条件分岐が必要なのか?」
Chefの最大の強みは「冪等性(べきとうせい)」です。何度実行しても、結果は常に同じ状態になること。しかし、単純な設定変更ならともかく、複雑なスクリプトを実行する場合、毎回実行されると困るケースがありますよね。
そこで使うのが `only_if` と `not_if` です。これらは「リソースが実行される前に、その条件を評価する」というガード節です。
- `only_if`: この条件が「真(終了コード0)」の時だけ実行する。
- `not_if`: この条件が「偽(終了コード0以外)」の時だけ実行する。
重要な評価タイミング
Chefがリソースを適用する際、まず `only_if`/`not_if` が評価されます。ここで「実行不要」と判断されれば、メインの処理は一切実行されません。これが「高速な収束」の秘訣です。
—
2. Rubyブロックを使った高度な条件判定
シェルスクリプトだけで条件を書くのは限界があります。ChefのレシピはRubyそのもの。Rubyの力を借りれば、もっと賢い判定が可能です。
例:特定のパッケージがインストール済み、かつ設定ファイルのハッシュ値が一致しない場合のみ処理を行う
execute ‘deploy_application’ do
command ‘/usr/local/bin/deploy.sh’
# Rubyブロックを使って、より複雑なロジックを判定
only_if do
# 1. 前提条件のチェック
package_installed = system(‘rpm -q my-app > /dev/null’)
# 2. ファイルの存在確認
config_exists = File.exist?(‘/etc/my-app/config.json’)
# 全ての条件が揃ったときだけ実行
package_installed && config_exists
end
end
このように、`only_if` にブロックを渡すと、そのブロックの戻り値(真偽値)で実行が制御されます。シェルスクリプトを呼び出すよりも高速で、かつRubyの柔軟な条件式が使えるため、現場では多用します。
—
3. 【極意】収束速度を最大化するアンチパターン回避
初心者が陥りやすいのが「重い処理をガード節に入れてしまう」ことです。
❌ アンチパターン:ガード節の中で重いコマンドを叩く
毎回 grep や find を実行すると、数千リソースある環境では地獄のように遅くなる
execute ‘update_config’ do
command ‘…’
not_if “grep ‘configured’ /var/log/my-app.log” # ログが巨大だとここで毎回待たされる
end
✅ プロの最適化:ファイルの特性を利用する
Chefには `creates` という強力な属性があります。`only_if` を書く前に、まずこれを使えないか検討してください。
execute ‘initialize_db’ do
command ‘/usr/bin/db_init.sh’
# ファイルが存在すれば実行しない。シェルを叩くより圧倒的に高速
creates ‘/var/lib/db/initialized.lock’
end
教訓:
1. シェルを実行するな: 可能な限り Ruby の `File` や `Dir` クラスを使え。
2. ガード節を軽くしろ: ログの検索や巨大なファイルのパースは避け、ステータスファイルやハッシュ値比較で判定せよ。
3. 冪等性を意識せよ: `execute` を使うときは、常に「この処理を二度実行しても安全か?」を自分に問いかけろ。
—
はじめの一歩:HelloWorld的な動作確認
初めてChefを触るなら、まずはこの「ガード節の挙動」を体感してください。
1. 環境: Chef Workstation をインストール。
2. レシピ作成 (`test.rb`):
1. ファイルがない時だけ作成
file ‘/tmp/hello.txt’ do
content ‘Hello, Chef!’
not_if { File.exist?(‘/tmp/hello.txt’) }
end
2. 上記のファイルが存在する時だけメッセージを表示
execute ‘check_file’ do
command ‘echo “File exists!”‘
only_if { File.exist?(‘/tmp/hello.txt’) }
end
3. 実行: `chef-apply test.rb` を2回叩いてみてください。
- 1回目:両方の処理が実行されます。
- 2回目:ガード節により、どちらも「Up-to-date(更新不要)」と判断され、即座に終了します。
—
最後に
Chefは単なる「コマンド実行ツール」ではありません。あなたのサーバーの状態を「定義(宣言)」する、インフラの設計図です。
`only_if` や `not_if` を使いこなすことは、サーバーの現状を深く理解し、無駄な処理を削ぎ落とす「職人の仕事」です。これをマスターすれば、あなたのコードは格段に安定し、チームメンバーから「なぜか君のレシピだけ爆速だね」と称賛されるはずです。
さあ、次はあなたの番です。コードの中に隠された「無駄な実行」を、今日から一つずつ消していきましょう。