[小ネタ] ECS サービスの初回デプロイメント時に、デプロイサーキットブレーカーが発動した場合の挙動を調べてみた
こんにちは!クラウド事業本部コンサルティング部のたかくに(@takakuni_)です。
みなさん、デプロイサーキットブレーカー使っていますでしょうか。
デプロイサーキットブレーカーを利用することで、異常なタスク数(起動に失敗するタスク数)が一定の閾値に達した時点で、自動的にロールバックが走るため、非常に便利な機能です。
ここで言うロールバックとは、「以前のデプロイメントに自動的に戻る」ことを指しているのですが、以前のデプロイメントがない状態の場合どうなるのでしょうか。
※「以前のデプロイメントがない状態
」とは、つまり、初回デプロイメントのことです。
今回は、初回デプロイメントが失敗し、デプロイサーキットブレーカーが発生した場合の挙動について、調べてみたいと思います。
結論
- 初回デプロイメントが失敗し、デプロイサーキットブレーカーが発生した場合、デプロイは ROLLOUT_FAIDED 状態に遷移する
- COMPLETED 状態にある最新のデプロイメントをロールバック先に選定するが、デプロイメントが存在しないため
- 場合によっては、新しい ECS タスクが残り続けるため、デプロイが成功しているように見える
- 必要に応じて、デプロイメントの失敗を通知すること
やってみる
今回は ELB のヘルスチェックに失敗して、タスク起動がこけているパターンを想定してみます。
以下のようにルートのみ、応答を返すコンテナを作ってみました。
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
ALB のヘルスチェックには /health
を指定します、
当たり前ですが、ELB のヘルスチェックには、失敗し続けている状態です。
デプロイメントを見てみる
デプロイメントを見てみます。デプロイのステータスは ロールバックに失敗
と表示されています。
サービスリビジョンは 1 と表示されており、ターゲットのみ表示されています。
また、作成時刻から初回デプロイで利用したタスクは、生き続けていることがわかります。
状況証拠的にまとめると、以下の状態であることがわかります。
- デプロイに失敗した(ELB のヘルスチェックが起因)
- ロールバックにも失敗した
- ELB のヘルスチェックは Unhealty である
- タスクの置き換わりは止まっている
一体、どういうことなのでしょうか。
ロールバックに失敗とは
そもそも、ロールバックに失敗
とは、どう言う状況なのでしょうか。
ドキュメントによると、 COMPLETED 状態にある最新のデプロイが見つからなかったため、ロールバックに失敗してしまったことが汲み取れます。
デプロイサーキットブレーカーは、デプロイが失敗したと判断すると、COMPLETED 状態にある最新のデプロイを探します。このデプロイをロールバックデプロイとして使用します。ロールバックが開始されると、デプロイは COMPLETED から IN_PROGRESS に変わります。つまり、デプロイは COMPLETED 状態になるまで次のロールバックの対象にはなりません。デプロイサーキットブレーカーが COMPLETED 状態のデプロイを見つけられない場合、サーキットブレーカーは新しいタスクを起動せず、デプロイは停止します。
今回は初回デプロイのため、以前のデプロイメントが見つからないため、ロールバックできなかったと考えられます。
タスクの置き換わりは止まっている
続いてタスクの置き換わりが止まっている部分です。
同じ箇所に記載されている「デプロイサーキットブレーカーが COMPLETED 状態のデプロイを見つけられない場合、サーキットブレーカーは新しいタスクを起動せず、デプロイは停止します。」に該当したと考えられます。
つまり、ECS によるタスクの置き換わりがストップし、ELB のヘルスチェックに失敗しているものの、タスクが動き続けている状態となっています。
ALB の特性上、すべてのターゲットがヘルスチェックにしている場合、フェイルオープンとなるため、ブラウザからは問題なさそうに見えますが、ヘルスチェックは失敗している状況となります。
ターゲットグループに異常な登録済みターゲットのみが含まれている場合、そのヘルスステータスにかかわらず、ロードバランサーはそれらすべてのターゲットにリクエストをルーティングします。つまり、有効なすべてのアベイラビリティーゾーン内で、すべてのターゲットが同時にヘルスチェックに失敗すると、ロードバランサーはオープンに失敗します。フェールオープンの効果は、ヘルスステータスにかかわらず、ロードバランシングのアルゴリズムに基づいて、有効なすべてのアベイラビリティーゾーン内のすべてのターゲットへのトラフィックを許可することです。
EventBridge の統合
上記のことから、マネコンを見ない限り、なぜか成功しているように見える現象も考えられます。
必要に応じて、EventBridge 経由で通知を飛ばすことも視野に入れておきましょう。例として次のイベントがデプロイメントの失敗時に拾えるようです。
{
"version": "0",
"id": "ddca6449-b258-46c0-8653-e0e3aEXAMPLE",
"detail-type": "ECS Deployment State Change",
"source": "aws.ecs",
"account": "111122223333",
"time": "2020-05-23T12:31:14Z",
"region": "us-west-2",
"resources": [
"arn:aws:ecs:us-west-2:111122223333:service/default/servicetest"
],
"detail": {
"eventType": "ERROR",
"eventName": "SERVICE_DEPLOYMENT_FAILED",
"deploymentId": "ecs-svc/123",
"updatedAt": "2020-05-23T11:11:11Z",
"reason": "ECS deployment circuit breaker: task failed to start."
}
}
まとめ
以上、「ECS サービスの初回デプロイメント時に、デプロイサーキットブレーカーが発動した場合の挙動を調べてみた」でした。
小ネタですが、私自身、デプロイサーキットブレーカーの挙動で、タスクが残り続けるとは思わなかったので、いい勉強になりました。
このブログがどなたかの参考になれば幸いです。クラウド事業本部コンサルティング部のたかくに(@takakuni_)でした!