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

FDE総合演習:倉庫に同じ注文が3回届いた

1.5.0 は受付済みと表示したが、倉庫に注文はなかった

TT Labで続きを見る

目標

releases/<バージョン>とcurrentのシンボリックリンクでデプロイし、ヘルスチェックとスモークの試験を経て、失敗したら直前のバージョンに戻して記録する、スクリプトを作ります。保存の整理で、currentと直前のバージョンを守ります。

なぜ重要なのか

ヘルスチェックは、プロセスが生きているかを、スモークは、業務が1件最後まで通るかを尋ねます。顧客の前回のデプロイは、前者の質問だけをして終わり、一晩中、注文を失いました。 バージョンをディレクトリで分け、シンボリックリンク1つで切り替えれば、ロールバックも同じ1つの動作になります。ただし、切り替える瞬間にcurrentが消えたり、古いプロセスが代わりに緑のランプをつけたり、整理のスクリプトが戻る先のバージョンを消したりすれば、構造があっても事故が起きます。 採点ツールは、毎回異なるバージョン番号で、正常なビルド・スモークでだけ壊れるビルド・起動した途端に落ちるビルド・起動が遅いビルドを作って、あなたのスクリプトを実行し、ログの文言ではなく、実際に応答しているバージョンとシンボリックリンクを、測り直します。

想定所要時間は60分です。デフォルトのセッションが終わる前に、+時間で延長してください(最大180分)。セッションが終わると、/rootのファイルは消えるので、スクリプトは別に保管してください。

ステップ

  1. ビルドorderapp-1.4.0.tar.gzを、/root/site/releases/1.4.0に展開し、currentのシンボリックリンクが、そのディレクトリを指すようにします(リンク: /root/site/current)。
  2. 切り替えのスクリプトを作ります(引数はROOTとバージョン、ファイル: /root/release/switch.sh)。存在しないバージョンは拒否し、currentが消える瞬間なしに、一度に切り替えます。
  3. デプロイのスクリプトを作ります(引数はROOT・ビルド・PORT、ファイル: /root/release/deploy.sh)。展開・切り替え・古いプロセスの入れ替え・ヘルスチェック(version確認)・スモークの注文・deploy.logの記録まで、正常なビルドで通します。
  4. deploy.shが、スモークに失敗したら、currentを直前のバージョンに戻し、そのバージョンを再び起動してから、rolled_back・reason smokeを記録し、終了コード2で終わるようにします。
  5. deploy.shのヘルスチェックで、起動した途端に落ちるバージョンはhealthで戻し、2.5秒遅れて起動する正常なバージョンは、待ってデプロイするようにします。待機の上限は10秒です。
  6. 整理のスクリプトを作ります(引数はROOTとKEEP、ファイル: /root/release/prune.sh)。mtimeが最新のKEEP個を残しますが、currentと直前のバージョンは、削除する一覧から除きます。
  7. 4回のデプロイ(最後はスモークの失敗)と、保存1の整理を続けて行っても、記録・残ったバージョン・応答しているバージョンが合っているかを確認します。
  8. 顧客の1.5.0を、deploy.shで/root/site(ポート8480)にデプロイして結果を見て、事件を記録します(ファイル: /root/release/incident.json)。

参考

最初のバージョンを手で展開してcurrentを設定する

ビルド1.4.0を/root/site/releases/1.4.0に展開し、currentのシンボリックリンクが、そこを指すようにしてください(リンク: /root/site/current)。

tarの-Cで、展開する場所を決めます。currentは、ディレクトリのコピーではなく、ln -sで作ったリンクでなければなりません。相対パスのリンク(releases/バージョン)は、デプロイのルートをまるごと移しても壊れません。

currentを一度に切り替える、切り替えのスクリプト

引数がROOTとバージョンの切り替えスクリプトを作ってください(ファイル: /root/release/switch.sh)。存在しないバージョンは、0以外のコードで拒否し、currentは、消える瞬間なしに切り替わる必要があります。

rename(2)は、既存の名前を原子的に置き換えます。同じディレクトリに一時的なリンクを作り、currentの上に移してください。mvには、対象がディレクトリを指していても、その中に入れないようにするオプションがあります。lnを使うなら、-nを抜かさないでください。

展開して、切り替えて、起動して、スモークまで行う

引数がROOT・ビルド・PORTのデプロイスクリプトを作って(ファイル: /root/release/deploy.sh)、正常なビルドをデプロイし、deploy.logにdeployedの1行を残してください。

バージョンは、tarの中のVERSIONから読みます。古いプロセスは、shared/app.pidで停止し、新しいアプリは、nohupと出力のリダイレクトで、バックグラウンドに起動します。ヘルスチェックの応答のversionが新バージョンか、スモークの注文(SMOKE-の接頭辞)がGETで読み直せるかを見ます。記録は、jq -cnで作ると、引用符の間違いがありません。

スモークが壊れたら、直前のバージョンに戻す

スモークの失敗時に、直前のバージョンへ切り替えて再起動し、rolled_back(reason smoke)を記録したあと、終了コード2で終わるようにしてください(ファイル: /root/release/deploy.sh)。

切り替えの前に、currentが指していたバージョンをpreviousとして覚えておかないと、戻る先がわかりません。ロールバックも、switch.shで行います。失敗したreleases/バージョンは、調査用に残します。

落ちたバージョンは素早く、遅いバージョンは待って

ヘルスチェックが、最大10秒待ちつつ、プロセスが落ちたら、すぐにhealthで戻すようにしてください(ファイル: /root/release/deploy.sh)。

1回失敗しただけで諦めると、起動が遅いだけの正常なバージョンを戻してしまいます。逆に、すでに落ちたプロセスを、10秒待つ理由はありません。kill -0 PIDは、シグナルを送らずに、プロセスがあるかどうかだけを確認します。

整理していて、戻る先のバージョンを消さない

引数がROOTとKEEPの整理スクリプトを作ってください(ファイル: /root/release/prune.sh)。mtimeが最新のKEEP個以外は消しますが、currentと直前のバージョンは残します。

ロールバックのあとは、currentが最新ではありません。直前のバージョンは、deploy.logで、resultがdeployedで、versionがcurrentである最後の行のpreviousです。ls -tは、更新時刻の新しい順に並べます。

4回デプロイして整理しても、合っている記録

4回のデプロイ(最後はスモークの失敗)と、保存1の整理を続けて行っても、記録と実際の状態が合うようにしてください(ファイル: /root/release/deploy.sh、/root/release/prune.sh)。

ロールバックしたデプロイのpreviousは、戻った先のバージョンです。そのあとで整理すると、最新の1つ(失敗したバージョン)と、currentと直前のバージョンが残る必要があります。一時的なデプロイのルートで、続けて自分で実行してみてください。

顧客の1.5.0をデプロイして、事件の記録を残す

deploy.shで1.5.0を/root/site(ポート8480)にデプロイし、結果を、failed_version・restored_version・reason・deploy_log_line・health_passedとして記録してください(ファイル: /root/release/incident.json)。

deploy_log_lineは、/root/site/deploy.logで、ロールバックの記録が何行目か(1から数えます)です。health_passedは、このバージョンがヘルスチェックを通過したかを書きます。app.logと記録のreasonから判断してください。採点ツールは、incident.jsonを、deploy.log・current・ビルドの元データと照合します。