ChefカスタムHandler完全開発ガイド:インフラ変更を「可視化」し、運用を自動化する極意
こんにちは。インフラエンジニアの皆さん、日々の運用で「誰が、いつ、どのサーバーに、どんな変更を加えたのか?」を追いかけるために、ログを漁って疲弊していませんか?
Chefを使っているなら、「カスタムHandler」をマスターしてください。これができると、Chefが実行されるたびに、その結果(成功・失敗・変更箇所)をSlackやDatadogへ自動的に飛ばすことができます。運用者が寝ている間も、インフラの状態を常に監視し、異常があれば即座に検知する。これこそが、SREとして自動化の恩恵を最大化するための第一歩です。
今回は、Chefの深淵に触れる「カスタムHandler」の開発手法を、現場でそのまま使えるレベルで解説します。
—
1. カスタムHandlerとは何か?
ChefのカスタムHandlerは、`chef-client`の実行サイクル(Converge)の終了直後に呼び出される「フック機能」です。
- 成功時: 何が変更されたのか(updated_resources)を通知する。
- 失敗時: どのリソースでエラーが起きたのか(backtrace)を通知する。
これらをフックすることで、Chefの実行結果をただのログファイルに閉じ込めるのではなく、「生きたデータ」として外部システムに送ることができるようになります。
—
2. 開発準備:環境を整える
まずは、Handlerを置くためのディレクトリをChefの構成内に用意します。
1. ディレクトリ作成: `files/default/handler` というディレクトリをクックブック内に作成します。
2. 構成: 最終的に以下のような構造になります。
my_notifier/
├── files/default/handler/slack_handler.rb
└── recipes/default.rb
—
3. HelloWorld:シンプルなカスタムHandlerの実装
まずは、Chefの実行終了時にコンソールにメッセージを出すだけの「Hello World」を作成しましょう。
`files/default/handler/slack_handler.rb` を作成します。
require ‘chef/handler’
class SlackHandler < Chef::Handler # reportメソッドがChef実行終了時に自動で呼ばれます def report if failed? Chef::Log.error("Chefの実行が失敗しました: #{run_status.exception}") else Chef::Log.info("Chef実行完了!変更されたリソース数: #{run_status.updated_resources.length}") end end end
このコードのポイント
- `Chef::Handler` を継承します。
- `run_status` オブジェクトには、実行結果の全て(例外、変更されたリソース、実行時間など)が詰まっています。これを使い倒すのがSREの腕の見せ所です。
—
4. 現場で使える「Slack通知Handler」の実装
次に、実際にSlackへ通知を送るための少し高度な実装例です。`net/http` を使い、JSONをペイロードとして送信します。
require ‘chef/handler’
require ‘net/http’
require ‘uri’
require ‘json’
class SlackHandler < Chef::Handler
def initialize(webhook_url)
@webhook_url = webhook_url
end
def report
# 変更があった場合、または失敗した場合のみ通知する(ノイズを減らす)
return unless failed? || updated_resources.any?
message = failed? ? "🚨 Chef Failure: #{node.name}" : "✅ Chef Success: #{node.name}"
payload = {
text: "#{message}\n変更リソース数: #{updated_resources.length}"
}
uri = URI.parse(@webhook_url)
Net::HTTP.post_form(uri, {'payload' => payload.to_json})
end
end
—
5. HandlerをChefに登録する
作成したHandlerを有効化するために、レシピ(`recipes/default.rb`)で登録処理を書きます。
Handlerファイルをクライアントノードに配布
cookbook_file “/var/chef/handlers/slack_handler.rb” do
source “handler/slack_handler.rb”
mode “0644”
end
Handlerを登録
chef_handler “SlackHandler” do
source “/var/chef/handlers/slack_handler.rb”
arguments [node[‘slack_webhook_url’]] # 設定値はAttributeから渡す
action :enable
end
—
6. 実戦投入のための「極限の知見」
初心者から脱却し、現場で信頼されるSREになるための3つのアドバイスです。
1. 非同期処理を意識する:
外部API(SlackやDatadog)への通信が遅いと、Chef全体の実行時間が伸びてしまいます。もし大規模な環境であれば、通知をバックグラウンドジョブとして処理するアーキテクチャを検討してください。
2. 例外処理を忘れない:
Handler自体がエラーを起こすと、Chefの実行全体が止まるリスクがあります。`begin-rescue`ブロックで、通信エラーが発生してもChefの実行には影響を与えない設計にしましょう。
3. テストには `ChefSpec` を活用:
`chef-client`をいちいち実行してテストするのは非効率です。ChefSpecを使って、Handlerが期待通りに`report`メソッドを呼び出すか、ユニットテストを書いてください。
—
最後に:なぜこれをするのか
インフラの変更を「黙って行う」のは、過去の遺物です。「変更を即座に可視化し、異常を即座に検知する」。このサイクルを作ることが、チームの心理的安全性を高め、障害発生時の初動を劇的に速くします。
今日からあなたのChefは、ただの構成管理ツールではなく、「インフラの番人」へと進化します。ぜひ、自分の環境で試してみてください。もし詰まったら、Chefのログを見ればすべてが書いてあります。それがChefの最高の教科書ですから。
さあ、自動化の世界へようこそ。またお会いしましょう。