二度回しても静かなプレイブックを作る
目標
同じプレイブックを何回実行しても、2回目からは何も変わらない状態を作り、その事実を、ログとレポートで証明します。
なぜ重要なのか
冪等性は、「きれいなコード」の問題ではなく、自動化を実際に使えるようにするための条件です。2回目の実行が安全だという確信があって初めて、cronで定期実行を設定してドリフトを捉えられ、パイプラインの途中で失敗したあとでも、ためらわずに再実行できます。逆に、毎回サービスを再起動するプレイブックは、人々に避けられるようになり、避けられる自動化は、ないも同然の自動化です。核心となる仕組みは、状態を知っているモジュール、シェルコマンドのガード(creates/changed_when)、そして変更があるときにだけ動くハンドラーです。特に、ハンドラーがプレイの最後にまとめて実行されるという点は、必ず覚えておいてください。途中でプレイが失敗すると、ハンドラーがまるごと消えて、「設定は変わったのに、サービスは古い設定を見ている」状態になります。
ステップ
/root/ans/idem/site.ymlを作成して実行し、出力を/root/ans/idem/out/run1.txtに保存してください。最初の実行のchangedは2以上である必要があります。- 同じプレイブックをもう一度実行して、
/root/ans/idem/out/run2.txtに保存してください。今回はchanged=0である必要があります。 reload appというハンドラーを定義して、設定を扱うタスクからnotifyで呼んでください。ハンドラーは、実行されるときに/root/ans/idem/artifacts/reload.markerを作成する必要があります。- 2回目の実行ログ(
run2.txt)に、RUNNING HANDLERがあってはいけません。最初の実行ログには、ある必要があります。 command/shellのタスクを1つ入れて、createsガードを付けてください。そのタスクは、/root/ans/idem/artifacts/stamp.txtに1行を書き込み、2回実行しても、ファイルに1行しかない必要があります。- 取得だけを行うタスクに
changed_whenを、失敗の判定が必要なタスクにfailed_whenを、それぞれ最低1回ずつ使ってください。 - プレイブックを
--checkで実行した出力を、/root/ans/idem/out/check.txtに保存してください。changed=0、failed=0である必要があります。 /root/ans/idem/out/idempotency.jsonを作成してください。run1_changed(2以上)、run2_changed(0)、handler_fired(1またはtrue)、verdict(「idempotent」という文字列)の4つのキーを含めます。
参考
- ラボのPodは、ラボごとに新しく起動します。
/root/ans/inventory/hosts.iniがなければ、最初のラボで作成したものと同じインベントリ(web1・web2・db1、ansible_host=127.0.0.1、ansible_port=2222、ansible_user=root、[prod:children]にweb・db)を、先に作り直してください。構造は、/opt/lab/fixtures/ansible/inventory.sample.iniを参考にすればよいです。 - PLAY RECAPの行の
changed=Nが、判定の基準です。 - ハンドラー名と
notifyの文字列は、正確に同じである必要があります。1文字違うだけで、静かに無視されます。 - よくある間違い1: テンプレートに時刻やランダムな値を入れて、毎回レンダリング結果が異なってしまうことです。そうすると、永遠に
changedが出ます。 - よくある間違い2:
shellでファイルへの追記(>>)をしながら、ガードを付けないことです。実行するたびに、行が積み上がります。
最初の実行で変更を作る
/root/ans/idem/site.ymlを作成して実行し、出力を/root/ans/idem/out/run1.txtに保存してください。最初の実行のchangedは2以上である必要があります。
ディレクトリ・ファイル・設定を作成するタスクが数個あれば十分です。実行結果の全体を、ファイルに残してください。
2回目の実行でchanged=0にする
同じプレイブックをもう一度実行して、/root/ans/idem/out/run2.txtに保存してください。今回はchanged=0である必要があります。
同じプレイブックをもう一度実行します。changedが0でなければ、どのタスクが犯人なのかを、ログから探してください。
ハンドラーを定義してnotifyで呼ぶ
reload appというハンドラーを定義して、設定を扱うタスクからnotifyで呼んでください。ハンドラーは、実行されるときに/root/ans/idem/artifacts/reload.markerを作成する必要があります。
ハンドラー名とnotifyの文字列が、正確に同じである必要があります。ハンドラーが動いたら、マーカーファイルを残すようにしてください。
2回目の実行でハンドラーが動かないようにする
2回目の実行ログ(run2.txt)に、RUNNING HANDLERがあってはいけません。最初の実行ログには、ある必要があります。
notifyは、タスクがchangedのときにだけ発火します。2回目の実行ログに、RUNNING HANDLERがあってはいけません。
シェルコマンドにcreatesガードを付ける
command/shellのタスクを1つ入れて、createsガードを付けてください。そのタスクは、/root/ans/idem/artifacts/stamp.txtに1行を書き込み、2回実行しても、ファイルに1行しかない必要があります。
コマンドが作成するファイルのパスをcreatesで知らせると、2回目からはスキップされます。ログが1行だけ積み上がる必要があります。
報告の基準を自分で決める
取得だけを行うタスクにchanged_whenを、失敗の判定が必要なタスクにfailed_whenを、それぞれ最低1回ずつ使ってください。
取得だけを行うコマンドは、changed_when: falseにし、失敗の判定が必要なところには、failed_whenを使ってください。
チェックモードでも変更がないことを確認する
プレイブックを--checkで実行した出力を、/root/ans/idem/out/check.txtに保存してください。changed=0、failed=0である必要があります。
すでに収束した状態なら、--checkの実行もchanged=0である必要があります。チェックモードをサポートしていないモジュールがあると、失敗します。
冪等性の判定レポートを作成する
/root/ans/idem/out/idempotency.jsonを作成してください。run1_changed(2以上)、run2_changed(0)、handler_fired(1またはtrue)、verdict(「idempotent」という文字列)の4つのキーを含めます。
2回の実行のchanged数と、ハンドラーの発火回数を、JSONにまとめて、判定の文字列を入れてください。