TT Lab
はじめる
学ぶ 学習パス コース

Ansible基礎

37台は成功と表示された — 失敗を設計する

TT Labで続きを見る

目標

1台だけが失敗するようにしたホスト3つのインベントリで、失敗を扱うつまみを1つずつ有効にして、そのたびに何が止まり何が続行するかを、マーカーファイルで直接確認します。

なぜ重要なのか

失敗は起こります。設計すべきことは、失敗をなくすことではなく、失敗したときに何が起きるかをあらかじめ決めておくことです。Ansibleのデフォルト値は、「失敗したホストだけが静かに外れ、残りは続行する」で、サーバーを1台ずつ独立して直す作業には良いデフォルト値であり、40台が1つのサービスを構成しているなら悪いデフォルト値です。そのため、このラボは、3つの質問を順に扱います。この失敗は本当の失敗なのか(failed_when)、失敗したそのホストはどうするのか(ignore_errors・block/rescue)、ほかのホストはどうするのか(any_errors_fatal・max_fail_percentage)。ここに、開始前に止めるassertと、失敗とは別の欄で数えるunreachableが加わると、デプロイレポートを読めるようになります。最後のステップで、そのレポートを自分で作成します。

ステップ

  1. /root/ans/err/hosts.iniに、webグループ(web1、web2)・dbグループ(db1)・ghostsグループ(ghost1)を書いてください。4つのホストすべてがansible_host=127.0.0.1、ansible_user=rootで、ポートはghost1だけが2223、残りは2222です。そして、/root/ans/err/p01.ymlで、web:dbに対して実行するプレイを作成してください。最初のタスクはweb2でのみ失敗し、2つ目のタスクは/root/ans/err/a1/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。実行出力は/root/ans/err/out/run1.txtに保存してください。
  2. /root/ans/err/p02.ymlを、ステップ1と同じ構造で作成し、失敗するタスクにignore_errorsを付け、マーカーは/root/ans/err/a2/reached-<호스트이름>に残してください(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run2.txtに保存します。今回は、3つのホストすべてにマーカーが残り、PLAY RECAPのignoredの欄が上がる必要があります。
  3. /root/ans/err/sample.confを、listen_port=8080・env=prod・workers=4の3行で作成してください。そして、/root/ans/err/p03.ymlで、web1でそのファイルにnosuchkeyが何回出てくるかを数えるタスクを作成してください。取得にすぎないので、変更として数えないようにし、見つからなくて出る終了コードは失敗にならないよう、基準を決めてください。続けて、その終了コードを/root/ans/err/a3/grep-rc.txtに1行で残し、出力は/root/ans/err/out/run3.txtに保存してください。
  4. /root/ans/err/p04.ymlで、web1に対して実行するプレイを作成してください。blockの中に、失敗するタスクと、その後に/root/ans/err/a4/never.txtを作成するタスクを置き、rescueは/root/ans/err/a4/rescued.txtに失敗したタスクの名前を書き込み、alwaysは/root/ans/err/a4/always.txtを残すようにしてください。出力は/root/ans/err/out/run4.txtに保存します。never.txtは作成されてはいけず、PLAY RECAPのrescuedが1である必要があります。
  5. /root/ans/err/p05.ymlをlocalhostに対して実行するプレイとして作成し、assertタスクを1つだけ置いてください。deploy_envがdev・stage・prodのうちのどれかを検査し、fail_msgは허용되지 않은 배포 환경입니다(韓国語で「許可されていないデプロイ環境です」を意味する文字列です)で始まって、現在の値も一緒に表示する必要があります。-e deploy_env=prodで実行した出力を/root/ans/err/out/assert-ok.txtに、-e deploy_env=qaで実行した出力を/root/ans/err/out/assert-fail.txtに保存してください。
  6. /root/ans/err/p06.ymlを、ステップ1と同じ構造で作成し、プレイにany_errors_fatalをオンにして、マーカーは/root/ans/err/a6/reached-<호스트이름>に残すようにしてください(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run6.txtに保存します。今回は、どのホストもマーカーを残せない必要があります。
  7. /root/ans/err/p07.ymlで、web:dbに対して実行するプレイを作成してください。max_fail_percentageは50、変数run_tagのデフォルト値はcontinue、変数doomedのデフォルト値はweb21つです。最初のタスクが/root/ans/err/a7/<run_tag>ディレクトリを作成し、次のタスクが、doomedに含まれるホストでのみ失敗し、最後のタスクが/root/ans/err/a7/<run_tag>/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。デフォルト値で1回実行して/root/ans/err/out/run7-continue.txtに、run_tagをabortにして、doomedにweb2とdb1を入れてもう1回実行して、/root/ans/err/out/run7-abort.txtに保存してください。
  8. /root/ans/err/p08.ymlをallに対して実行するプレイとして作成してください。最初のタスクはpingですが、到達できないものは無視し、2つ目のタスクは/root/ans/err/a8/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run8.txtに保存してください。そして、実行記録ファイル1つを引数として受け取り、hosts=N ok=N changed=N unreachable=N failed=N skipped=N rescued=N ignored=Nの1行を出力する/root/ans/err/recap.shを書き、それで/root/ans/err/out/failure-report.jsonを作成してください。キーは、default_failed(ステップ1の実行のfailedの合計)・ignored(ステップ2)・rescued(ステップ4)・unreachable(ステップ8)・fatal_reached(a6のマーカーの数)・maxfail_reached(a7/continueのマーカーの数)の6つで、値はすべて数値です。

参考

デフォルトの動作: 失敗したホストだけが外れる

/root/ans/err/hosts.iniに、webグループ(web1、web2)・dbグループ(db1)・ghostsグループ(ghost1)を書いてください。4つのホストすべてがansible_host=127.0.0.1、ansible_user=rootで、ポートはghost1だけが2223、残りは2222です。そして、/root/ans/err/p01.ymlで、web:dbに対して実行するプレイを作成してください。最初のタスクはweb2でのみ失敗し、2つ目のタスクは/root/ans/err/a1/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。実行出力は/root/ans/err/out/run1.txtに保存してください。

ホストがすべて同じsshdに接続するので、「この1台だけ失敗」は、ファイルではなくinventory_hostnameの条件で作ります。ghost1のポートは、誰も待ち受けていない番号なので、ステップ8で、到達できないホストの役を果たします。プレイブックが0以外の値で終了するので、出力を保存するとき、スクリプトがそこで止まらないようにしてください。

結果だけを無視すると、何が変わるか

/root/ans/err/p02.ymlを、ステップ1と同じ構造で作成し、失敗するタスクにignore_errorsを付け、マーカーは/root/ans/err/a2/reached-<호스트이름>に残してください(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run2.txtに保存します。今回は、3つのホストすべてにマーカーが残り、PLAY RECAPのignoredの欄が上がる必要があります。

ignore_errorsは、判定を変えずに、結果だけを無視します。そのため、タスクは依然として失敗として記録されますが、ホストは外れません。PLAY RECAPで、failedではなく、どの欄が上がるかを、自分で見てください。

何を失敗と見なすかを自分で決める

/root/ans/err/sample.confを、listen_port=8080・env=prod・workers=4の3行で作成してください。そして、/root/ans/err/p03.ymlで、web1でそのファイルにnosuchkeyが何回出てくるかを数えるタスクを作成してください。取得にすぎないので、変更として数えないようにし、見つからなくて出る終了コードは失敗にならないよう、基準を決めてください。続けて、その終了コードを/root/ans/err/a3/grep-rc.txtに1行で残し、出力は/root/ans/err/out/run3.txtに保存してください。

探す単語がなければ1が出て、ファイルがない、または引数が間違っていれば、2以上が出ます。前者は答えで、後者がエラーです。registerで受け取った結果の終了コードで、基準を書いてください。ignore_errorsで覆うこととは、別のことです。このプレイブックは、failed=0できれいに終わる必要があります。

block・rescue・alwaysでロールバックを構造にする

/root/ans/err/p04.ymlで、web1に対して実行するプレイを作成してください。blockの中に、失敗するタスクと、その後に/root/ans/err/a4/never.txtを作成するタスクを置き、rescueは/root/ans/err/a4/rescued.txtに失敗したタスクの名前を書き込み、alwaysは/root/ans/err/a4/always.txtを残すようにしてください。出力は/root/ans/err/out/run4.txtに保存します。never.txtは作成されてはいけず、PLAY RECAPのrescuedが1である必要があります。

失敗したタスクの名前は、rescueの中でだけ使える変数に入っています。名前にfailedとtaskが含まれます。rescueが最後まで成功すると、そのホストは失敗していないものとして扱われて、緑になります。そのため、ロールバックが実行された証拠をファイルに残すことが、この構造の半分です。

前提が食い違ったら、何かを触る前に止まる

/root/ans/err/p05.ymlをlocalhostに対して実行するプレイとして作成し、assertタスクを1つだけ置いてください。deploy_envがdev・stage・prodのうちのどれかを検査し、fail_msgは허용되지 않은 배포 환경입니다(韓国語で「許可されていないデプロイ環境です」を意味する文字列です)で始まって、現在の値も一緒に表示する必要があります。-e deploy_env=prodで実行した出力を/root/ans/err/out/assert-ok.txtに、-e deploy_env=qaで実行した出力を/root/ans/err/out/assert-fail.txtに保存してください。

デフォルトの失敗メッセージは1行だけなので、条件が複数あると、どれが偽だったのかがわかりません。現在の値をメッセージに埋め込んでおけば、ログ1行で終わります。コマンドラインの変数は、プレイのvarsより強いので、同じプレイブックを、値だけを変えて2回実行できます。採点ツールも、同じ方法でこのプレイブックを直接実行してみます。

1台でも失敗したら、すべてを止める

/root/ans/err/p06.ymlを、ステップ1と同じ構造で作成し、プレイにany_errors_fatalをオンにして、マーカーは/root/ans/err/a6/reached-<호스트이름>に残すようにしてください(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run6.txtに保存します。今回は、どのホストもマーカーを残せない必要があります。

このつまみは、プレイのレベルに付きます(タスクではありません)。失敗していないホストも、残りのタスクを実行しないので、マーカーのディレクトリは空になります。PLAY RECAPで、失敗していないホストのokの欄がどうなるかを見てください。マーカーのディレクトリは、あらかじめ作成しておく必要があります。そうすれば、「空である」と「ない」を区別できます。

何台までは耐えるか: 割合で決める

/root/ans/err/p07.ymlで、web:dbに対して実行するプレイを作成してください。max_fail_percentageは50、変数run_tagのデフォルト値はcontinue、変数doomedのデフォルト値はweb21つです。最初のタスクが/root/ans/err/a7/<run_tag>ディレクトリを作成し、次のタスクが、doomedに含まれるホストでのみ失敗し、最後のタスクが/root/ans/err/a7/<run_tag>/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。デフォルト値で1回実行して/root/ans/err/out/run7-continue.txtに、run_tagをabortにして、doomedにweb2とdb1を入れてもう1回実行して、/root/ans/err/out/run7-abort.txtに保存してください。

3台のうち1台は33パーセント、2台は66パーセントです。基準を超えたかどうかが、分かれ道です。リスト変数をコマンドラインで上書きするときは、JSONでまるごと渡すと楽です。マーカーのディレクトリを作成するタスクを、失敗するタスクより前に置いてください。そうすれば、止まった実行でも、空のディレクトリが残ります。

到達できないホストと、6回の実行を1枚にまとめる

/root/ans/err/p08.ymlをallに対して実行するプレイとして作成してください。最初のタスクはpingですが、到達できないものは無視し、2つ目のタスクは/root/ans/err/a8/reached-<호스트이름>を残します(プレースホルダーはホスト名です)。出力は/root/ans/err/out/run8.txtに保存してください。そして、実行記録ファイル1つを引数として受け取り、hosts=N ok=N changed=N unreachable=N failed=N skipped=N rescued=N ignored=Nの1行を出力する/root/ans/err/recap.shを書き、それで/root/ans/err/out/failure-report.jsonを作成してください。キーは、default_failed(ステップ1の実行のfailedの合計)・ignored(ステップ2)・rescued(ステップ4)・unreachable(ステップ8)・fatal_reached(a6のマーカーの数)・maxfail_reached(a7/continueのマーカーの数)の6つで、値はすべて数値です。

到達できないことは、タスクの失敗ではなく接続の失敗なので、無視するための引数が別にあります。その引数は、付けたタスクにだけ効き、無視することにしても、プレイブックの終了コードは0ではありません。合算は、PLAY RECAPの行の下だけを読む必要があります。上のタスクの出力にも、似た文字が混ざっているからです。採点ツールは、自分で作成した記録ファイルでも、このスクリプトを実行してみるので、答えを書いておいただけのスクリプトは、通過できません。