Amazon Web Services ブログ

Amazon ECS のタスクヘルスとタスク置換の詳細

はじめに

Amazon Elastic Cotainer Service (Amazon ECS) は、AWS 上で毎週何十億ものアプリケーションコンテナのライフサイクルを管理しているコンテナオーケストレーションサービスです。Amazon ECS の主な目標の 1 つは、運用者にかかる諸々の負担を取り除くことです。Amazon ECS はアプリケーションコンテナを 24 時間 365 日監視し、予期しない変化に人間よりも迅速かつ適切に対応できます。Amazon ECS は、アプリケーションコンテナのデプロイを継続的に自己修復してあるべき状態に戻すことで、アプリケーションのクラッシュやハードウェア障害などの望ましくない変更に対応します。また、トラフィックの急増など、アプリケーションが停止する原因となる外部要因もあります。こうした要因には対処が難しい場合があります。この投稿では、Amazon ECS がタスクの正常性の問題とタスク置換を処理する方法に最近加えられた変更と、これらの変更によって Amazon ECS でオーケストレーションされたアプリケーションの可用性がどのように向上するかについて詳しく説明します。

タスクの正常性評価

Amazon ECS はいくつかの基準に基づいてタスクの正常性を評価します。

  1. まず、タスクが正常であるためには、必須とマークされているすべてのコンテナが実行されている必要があります。すべての Amazon ECS タスクには、少なくとも 1 つの必須コンテナが必要です。ベストプラクティスに則ったコンテナは 1 つのアプリケーションプロセスを実行し、重大なランタイム例外によってそのプロセスが終了すると、コンテナは停止します。停止したコンテナが必須とマークされていた場合は、タスク全体が正常でないと見なされ、タスクを置き換える必要があります。
  2. Amazon ECS タスク定義を使用して、Amazon ECS エージェントがコンテナ内で定期的に実行する内部ヘルスチェックコマンドのオプションを設定できます。このコマンドは、成功を示す終了コード 0 を返すことが期待されています。0 以外の終了コードが返された場合は、失敗したことを意味します。その場合コンテナは異常と見なされます。必須コンテナに異常があるためタスクも異常と見なされ、Amazon ECS がタスクを置き換えます。
  3. Amazon ECS サービスを使用して、アプリケーションコンテナと他の AWS サービスとの間のアタッチメントを設定できます。たとえば、コンテナデプロイを Elastic Load Balancing (ELB) または AWS Cloud Map に関連づけることができます。これらのサービスは独自の外部ヘルスチェックを行います。たとえば、ELB は定期的にコンテナへの接続を開いてテストリクエストを送信しようとします。その接続を開くことができない場合や、コンテナが予期しない応答を返した場合、またはコンテナの応答に時間がかかりすぎる場合、ELB はターゲットコンテナが異常であると見なします。Amazon ECS は、Amazon ECS タスクが正常か異常かを判断する際に、この外部のヘルスステータスも考慮します。ELB ヘルスチェックに異常があると、タスクは置き換えられます。

タスクが正常であるためには、すべてのヘルスステータスのソースが正常と評価されなければなりません。いずれかのソースが異常ステータスを返した場合、Amazon ECS タスクは異常と見なされ、置き換えられます。

タスク置換動作

Amazon ECS タスクの置換は、主に次の 2 つの状況で行われます。

  1. UpdateService API コールによって新しいデプロイがトリガーされる場合。以前のデプロイに含まれる既存のタスクを、新しいデプロイに含まれる新しいタスクに置き換える必要があります。
  2. アクティブなデプロイの内、既存のタスクに異常が生じた場合。正常なタスクの数を維持するには、異常なタスクを置き換える必要があります。

Amazon ECS は黎明期から、ローリングデプロイ中のタスク置換の動作については、Amazon ECS サービスの 2 つのプロパティを使用して設定可能でした。

  • maximumPercent – これにより、Amazon ECS がサービスの希望するタスク数を超えて起動できる追加タスクの数がコントロールされます。たとえば、maximumPercent が 200% で、サービスの希望するタスク数が 8 タスクの場合、Amazon ECS は合計で 16 タスクまで追加タスクを起動できます。
  • minimumHealthyPercent – これにより、デプロイ中に Amazon ECS サービスの希望するタスク数を下回ることが許される割合がコントロールされます。たとえば、minimumHealthyPercent は 75% で、サービスに必要なタスク数は 8 タスクとします。その場合、Amazon ECS は 2 つのタスクを停止して、サービスのデプロイメントを実行中のタスクを 6 つに減らすことができます。

maximumPercentminimumHealthyPercent は、Amazon Elastic Compute Cloud (Amazon EC2) 上で Amazon ECS タスクを実行するときに、ローリングデプロイの動作を微調整するための効率的な制御として長年機能してきました。しかし、これらのデプロイコントロールは、ますます多くの Amazon ECS ユーザーがサーバーレスの AWS Fargate を選択している世界ではあまり意味がありません。AWS Fargate の使用率は、クラスターに登録した Amazon EC2 インスタンスの数によって制約されないため、モダンアプリケーションではローリングデプロイ中に実行タスク数が希望する数を下回ったり、起動される追加タスクの数を減らしたりすることを Amazon ECS に要求する必要がありません。

さらに、問題のあるタスクを置き換えるという点では、もともと maximumPercentminimumHealthyPercent によるコントロールは無視されていました。タスクが異常になると、サービスの必要数が minimumHealthyPercent で定義されたしきい値を大幅に下回る可能性があります。たとえば、8 つのタスクを実行していて、そのうちの 4 つに異常が生じた場合、Amazon ECS は 4 つの異常なタスクを終了し、4 つの代替タスクを起動します。実行中のタスクの数は、一時的に必要な数の 50% まで下がってしまいます。

Amazon ECS による異常なタスクの置き換え方法がアップデートされました

2023 年 10 月 20 日より、Amazon ECS は異常なタスクを置き換えるときに可能な限り maximumPercent を使用するようになりました。この仕組みを理解するために、いくつかのシナリオを見てみましょう。

タスクのクラッシュ

あなたは希望するタスク数が 8 つ、最大パーセントが 200% のサービスを実行しています。8 つのタスクのうちの 4 つに重大な実行時例外が発生しています。そのプロセスがクラッシュして終了し、重要なコンテナが終了してしまいました。Amazon ECS は、必須コンテナが終了したことで 8 つのタスクのうちの 4 つに異常が発生したことを観測しました。残念なことに、異常なコンテナがクラッシュしたため、Amazon ECS の正常稼働率が 100% を下回ることを避けられません。実行中タスクの数は一時的に希望の数の 50% まで下がりますが、Amazon ECS は実行中タスクの数を希望の 8 タスクに戻すために、できるだけ早く 4 つの代替タスクを開始します。

フリーズされたタスク

あなたは希望するタスク数が 8 つ、最大パーセントが 200% のサービスを実行しています。コード内の無限ループが原因で、8 つのタスクのうちの 4 つはフリーズしますが、プロセスは実行されたままです。アタッチされたロードバランサーはサービスにヘルスチェックリクエストを送信し、ターゲットコンテナがヘルスチェックリクエストに応答しなくなったため、ターゲットに異常があるとマークしました。Amazon ECS は、これら 4 つのフリーズされたタスクを異常と見なします。サービスの最大パーセントでは、最大 16 個のタスクを処理できます。Amazon ECS は、異常な 4 つのタスクに対する 4 つの代替タスクを起動し、実行中タスクは合計 12 個になります。追加した 4 つのタスクが正常になると、Amazon ECS は異常な 4 つのタスクを停止します。これにより、実行中のタスク数は必要な 8 タスクに戻ります。

過負荷のタスク

あなたは希望するタスク数が 8 つ、最大パーセントが 150% のサービスを実行しています。サービスには Auto Scaling ルールがアタッチされています。また、ロードバランサーも接続されており、ロードバランサーを経由して大量のトラフィックが流入します。トラフィックが急増するため、タスクからの応答時間が大幅に遅くなります。応答時間が遅くなると、ロードバランサーのヘルスチェックが失敗し、ELB は 8 つのターゲットすべてを異常とマークします。ELB は正常なターゲットがないためオープンに失敗し、すべてのターゲットにトラフィックを分散し続けます。

Amazon ECS は、8 つのタスクすべてが正常でないことを観測します。そして、Amazon ECS はこれらの異常なタスクを置き換えようとします。最大パーセントを 150% に設定すると、サービスは最大 12 個の実行中タスクを起動できます。そのため、Amazon ECS は異常な実行中タスクを直ちに停止することはしません。代わりに、既存の 8 つの正常でないタスクと並行して 4 つの代替タスクを起動します。幸いこれらの 4 つの追加タスクにより、ELB はより多くのターゲットにトラフィックを分散できるようになります。実行中の 12 個のタスクはすべてタイムアウトすることなく受信トラフィックを処理できるようになり、正常性が安定します。Amazon ECS は、正常に実行されているタスクが 12 個であることを観測します。

同時に、元の 8 つの実行中タスクの CPU 使用率が高いことが観測されたことに基づいて、アプリケーションの Auto Scaling ルールが実行されました。このルールにより、Amazon ECS サービスに必要な実行中タスクの数が 8 個から 10 個に更新されました。そのため、Amazon ECS は 12 個の正常に実行されているタスクのうちの 2 つだけを停止します。これにより、タスク数は必要な実行中タスク数である 10 個まで減少します。

制限された最大パーセント

あなたは必要なタスク数が 8 つのサービスを実行していますが、ダウンストリームの制限またはインフラストラクチャの制約により、最大パーセントを 100% に設定しています。これでは、実行中の 8 つのタスクと並行して、Amazon ECS が追加のタスクを起動することはできません。このデプロイのタスクがフリーズしたり、過負荷になってヘルスチェックに失敗し始めたら、Amazon ECS はそのタスクを置き換える必要があります。Amazon ECS はまず異常なタスクを停止し、異常なタスクが停止された後に代替タスクを起動します。つまり、実行中のタスク数は依然として一時的に必要な数を下回っています。

ローリングデプロイ中にタスクがヘルスチェックに失敗

あなたは希望するタスク数が 8 つ、最大パーセントが 150% のサービスを実行しています。ローリングデプロイを行い、新しいタスク定義に基づいて実行中タスクを更新しました。最大パーセントは 150% なので、Amazon ECS は現在実行中のタスクと並行して追加のタスクを起動できます。ローリングデプロイでは、すでに 4 つの追加タスクの起動がトリガーされています。現在、このサービスには 12 個の実行中タスク (8 個の古いタスクと 4 つの新しいタスク) があります。

このローリングデプロイの最中に、予期しないバグが原因で、古いタスクの一部がヘルスチェックに失敗してしまいました。アクティブなローリングデプロイが行われているため、Amazon ECS は異常なタスクを直ちに終了し、できるだけ早く新しいタスクのインスタンスに置き換えます。ローリングデプロイ中、Amazon ECS は常に失敗したタスクを新しいアクティブなデプロイのタスクに置き換えようとします。

外部要因による継続的なタスク障害

あなたは希望するタスク数が 8 つ、最大パーセントが 150% のサービスを実行しています。コードが依存しているダウンストリームサービスの 1 つが予期しない応答を返し始め、その結果、コードがヘルスチェックに失敗し始めました。Amazon ECS は 8 つのタスクに異常があり、置き換える必要があると判断したため、8 つの初期タスクと並行して、4 つの代替タスクを追加で起動します。この時点で、12 個のタスクが実行されています。8 個は元のタスク、4 個は代替タスクです。残念ながら、代替タスクは元のタスクと同じ信頼性の低いダウンストリームサービスに依存しているため、12 個のタスクはすべて正常ではありません。

代替タスクが安定せず、Amazon ECS は異常なタスクの数がサービスに必要な数よりも多いと判断したため、異常なタスクの数を必要な数に戻すために、異常なタスクの 4 つをランダムに停止します。Amazon ECS は、問題のあるタスクのうちどのタスクが「元のタスク」で、どのタスクが「代替タスク」であったかについて、ステートフルな情報を保持していません。異常なタスクが十分に停止され、さらにタスクを追加する余地ができたら、ECS は代替タスクを再び開始しようとします。これは、ダウンストリームのサービスが再び信頼できる状態になるか、障害状態をより適切に処理するコード更新が UpdateService API 呼び出しによってロールアウトされるまで、無限に続きます。

ヘルスチェックとワークロードの急増への迅速な対応

以前は、Amazon ECS は常に異常なタスクを最初に停止し、次に代替タスクを起動していました。この動作は、既存のタスクを停止せずに代替タスクを起動する余地がない、静的なサイズの Amazon EC2 インスタンスからなるクラスターにタスクが密集して binpack (タスク配置戦略の 1 つ) されている世界では理にかなっています。しかし、最近では、サーバーレスの AWS Fargate キャパシティーを使用して実行されているコンテナワークロードが増えています。AWS Fargate は必要に応じてオンデマンドのコンテナ容量を提供できるため、実行中タスクを中断して代替タスクのための余地を作る必要はありません。さらに、Amazon EC2 上で Amazon ECS を利用しているお客様の多くは、Amazon EC2 インスタンスからなる静的なサイズを持つクラスターにデプロイするのではなく、Amazon ECS キャパシティプロバイダーを利用してオンデマンドで追加の Amazon EC2 インスタンスを起動するようにしています。そのため、現在 Amazon ECS ではサービスの maximumPercent の使用を優先し、代替タスクが正常になるまで異常なタスクを可能な限り実行し続けます。

さらに、Amazon ECS の新しいタスク置換動作により、高負荷なタスクが終了するのを防ぐことができます。ワークロードが急増すると、場合によってはデプロイの内のいくつかのタスクが異常になり、その結果タスクが置き換えられてしまいます。しかし、Amazon ECS が代替タスクを起動するために異常なタスクを停止すると、ロードバランサーは残りの正常なタスクに多くのワークロードを移してしまい、その結果、それらのタスクは異常な状態になります。短時間のうちに、全ての正常なタスクに負荷がかかると、ヘルスチェックの失敗が次々に発生し、すべてのタスクに異常が生じてしまいます。

最終的には、アプリケーションの Auto Scaling ルールが実行され、デプロイメントがワークロードを処理するのに十分なサイズにスケールアップされます。しかし、ほとんどの場合、トラフィックが急増すると集計されたリソース消費量に基づくオートスケールがトリガーされる前に、ロードバランサーのヘルスチェックが失敗します。Auto Scaling ルールは、コンテナデプロイメントをスケールアウトして対応する前に、少なくとも 1 分間の高い平均リソース使用率を監視する必要があります。ただし、過負荷のタスクでは、ロードバランサーのヘルスチェックがすぐに失敗する可能性があります。

大量のワークロードを処理しているためにタスクが正常でないシナリオでは、Amazon ECS の新しいタスク置換動作により、サービスの可用性と信頼性が大幅に向上します。Amazon ECS はヘルスチェックの失敗を検知し、Auto Scaling ルールがトリガーされる前に、入ってくるワークロードの急増に対応できるようにするための代替タスクを事前に並行起動します。Auto Scaling ルールがトリガーされると、代替タスクと元のタスクの両方が正常でサービスの現在の必要なタスク数を満たしていれば、両方のタスクを保持します。

結論

この投稿では、異常なタスクを処理するときの Amazon ECS の新しい動作について説明しました。ミッションクリティカルなアプリケーションに Amazon ECS を採用するお客様が増えるにつれ、私たちは常に困難で新しいオーケストレーション問題に大規模に取り組むことに喜びを感じています。この最新のタスク置換動作は、規模の大小を問わずお客様のニーズに応えられるように設計されています。これにより、アプリケーションの障害やトラフィックの急増などの不利な状況でも、コンテナのデプロイメントをオンラインかつ可用性の高い状態に保つことができます。

Amazon ECS の今後の追加機能の詳細や、独自の課題を作成して変更や新機能をリクエストするには、Amazon ECS パブリックロードマップをご覧ください。

Amazon ECS スケジューラーの動作の詳細については、公式ドキュメントのサービススケジューラーの概念を参照してください。

本記事は A deep dive into Amazon ECS task health and task replacement (2023 年 11 月 3 日公開) を翻訳したものです。翻訳は、ソリューションアーキテクトの吉田が担当しました。