Amazon Web Services ブログ

Amazon Elastic Container Service のレジリエンスと可用性を Dive Deep

はじめに

この投稿では、Amazon Elastic Container Service (Amazon ECS) におけるアーキテクチャの原則について詳しく説明し、Amazon ECS におけるアプリケーションの高可用性とレジリエンス(回復力)を実現しやすくする機能のいくつかを概説します。Amazon ECS が AWS の可用性と回復力のパターンをどのように活用するように設計されているのか、そして Amazon ECS API などを利用してそうした考え方をどのように簡単に利用できるようになっているのかについて見ていきましょう。これにより、お客様のソリューションの要求に最適な Amazon ECS 構成と機能を選択できるようになると考えています。
AWS の目標は、お客様がビジネスの革新に集中できるように「差別化に繋がらない重労働」を取り除くことです。モダンアプリケーションの多くは、さまざまな障害モードに耐え、高い可用性を備えていることが求められます。回復力と可用性の高いソリューションを構築することは、困難で時間がかかることがあり、多くの場合その投資はビジネスの成功には不可欠ですが、それだけではソリューションを顧客に提供する際の差別化にはなりません。
Amazon ECS は AWS のフルマネージドのコンテナオーケストレーションサービスであり、Amazon Elastic Compute Cloud (Amazon EC2)AWS Fargate 、または Amazon ECS Anywhere を通じてオンプレミスのハードウェア上でコンテナ化されたアプリケーションを効率的にデプロイ、管理、スケーリングするのに有用です。 Amazon ECS は、AWS が使用している技術を活用して、高可用性を実現しやすくするように構築されています。お客様は Amazon ECS を有効に活用いただくことにより、自社とビジネスを真に差別化する重要な要素であるアプリケーションに集中することができます。

ソリューションの概要

可用性とレジリエンス(回復力)

障害の軽減について検討する際には通常、次の 2 つの領域について検討する必要があります。

  • そのソリューションはどの程度の可用性が必要なのか
  • そのソリューションにはどの程度の回復力が必要なのか

可用性は、ソリューションが有用な作業を行える確率です。たとえば、ソリューションがカップケーキを販売する Web サイトである場合、ソリューションの可用性は、顧客がいつでもカップケーキを正常に購入できるかどうかで測定できます。ある時点で顧客がカップケーキの購入を完了できなければ、可用性の指標に悪影響を及ぼします。
回復力は可用性に影響しますが、微妙に異なります。回復力とは、悪条件下でも運用を継続できる能力と、通常の運用に戻る速さのことです。カップケーキの例では、顧客が最初に失敗した時点からどれだけ速くカップケーキを購入できるようになるか、で回復力を測ります。別の言い方をすれば可用性は、ある期間にわたってソリューションが動作しなくなった時間の比率として測定でき、回復力は、障害からの回復にかかる平均時間として測定できます。
Amazon ECS のコントロールプレーンを設計する際、私たちはこの 2 つの概念を深く検討し、両方に対応できるサービスとして設計しました。最初に、Amazon ECS がどのように設計され可用性を向上させることができるのかを探り、次に Amazon ECS がどのように設計及び管理されて回復力を向上させているかを確認していきます。

可用性

アプリケーションの稼働期間中に何らかの障害が発生することはほぼ間違いないと考えていいでしょう。AWS の設計で考慮しているのは、予期せぬ事態を想定することです。予期していなかった理由で、ある時点で何かがおかしくなることが起こりえます。障害率が非常に低い場合であっても規模が十分に大きい場合には、一定の規模の障害が発生することが想定されます。たとえば、99.99% の可用性で 100 万台のサーバーがある場合、これらのサーバーのうち、いつでも約 100 台に障害が発生すると予想されます。これに対応するため、AWS では、障害が通常の運用の一部であると想定してサービスを設計するようにしています。Amazon ECS では、この考え方を管理レイヤーのサービス設計に取り入れ、Amazon ECS 上に展開されるアプリケーションでも同じことを行うメカニズムを提供する機能を構築しました。

アベイラビリティーゾーンを使用した静的安定性

AWS は、AWS リージョンとアベイラビリティーゾーンの階層構造を通じて、冗長性の高いインフラストラクチャをお客様に提供します。各 AWS リージョンでは、shared-nothing パターンが採用されています。つまり、各リージョンは他のリージョンから分離され、独立しているため、あるリージョンで起きた障害は他のリージョンには影響を及ぼしません。各 AWS リージョンは複数のアベイラビリティーゾーンによって構成されています。アベイラビリティーゾーンは、ネットワーク遅延の問題を回避するために地理的に十分近接していますが、相関的な障害を避けることを意図して冗長で独立した運用を行えるように、リージョン内に地理的に分散しています。アベイラビリティーゾーンは、それぞれが独自の冗長電源、ネットワーク、およびアベイラビリティーゾーン間接続を備えた 1 つ以上の個別のデータセンターで構成されます。これらのリージョンとアベイラビリティーゾーンという 2 つの構成要素は、可用性の高いサービスを構築するための基盤となります。
Becky Weiss と Mike Furr は、「アベイラビリティーゾーンを使用した静的安定性 」という記事で、「静的安定性」の意味について説明しています。その記事では AWS のサービスが、アベイラビリティーゾーン全体で事前にスケーリングされたアクティブ – アクティブステートレスサービスをどのように活用するか概説しています。Amazon ECS コントロールプレーンは、多数の個別サービスで構成されるマイクロサービスアーキテクチャとなっています。これらのマイクロサービスは、Becky と Mike の記事で概説されているアクティブ – アクティブパターンに基づいて、AWS インフラストラクチャを使用して可用性を最大化するように設計されています。Amazon ECS は、サービス全体の完全かつ独立したコピーがすべてのリージョンにデプロイされています。各マイクロサービスは、リージョン内のすべてのアベイラビリティゾーンにデプロイされ、少なくとも 3 つのアベイラビリティゾーンにまたがってピーク負荷の 150% 以上のオーバープロビジョニングが行われます。これにより 1 つのアベイラビリティーゾーンで障害が発生した場合でも、Amazon ECS は残りのアベイラビリティーゾーンによってマイクロサービスの稼働に十分なキャパシティを確保しているため、お客様のリクエストに応え続けることができます。

Availability-Zones

Amazon ECS サービスと配置戦略

ワークロードは、コンソール、AWS コマンドラインインターフェイス (AWS CLI)、または Amazon ECS API を介して直接 Amazon ECS クラスターにプロビジョニングされます。クラスターで実行されているワークロードのインスタンス を起動方法に関係なく「タスク」と呼びます。Amazon ECS のコントロールプレーンは、各マイクロサービスのコピーが少なくとも 3 つのアベイラビリティーゾーンで実行されていることを確認することで、基盤となるインフラストラクチャの障害による影響を軽減します。これと同様の考え方を適用することで、お客様のワークロードにおいて同様の可用性を実現することができます。Amazon ECS を Amazon EC2 で使用する場合、AWS リージョンにおいて利用可能である必要な数のアベイラビリティーゾーンにわたって、サービス内のタスクに spread 戦略を使用するようにサービスを設定します。

Spread-placement

Amazon EC2 で Amazon ECS を使用する際にワークロードがアベイラビリティーゾーン全体に分散されるようにするには、それらのアベイラビリティーゾーンのクラスターに Amazon EC2 キャパシティーが登録されていることを確認する必要があります。Amazon EC2 Auto Scaling グループ (ASG) キャパシティープロバイダーをクラスターに登録し、Amazon EC2 Auto Scaling グループが複数のアベイラビリティーゾーンで Amazon EC2 インスタンスを起動するように設定されていることを確認します。Amazon EC2 のキャパシティが複数のアベイラビリティーゾーンに分散されている場合、タスク配置をアベイラビリティーゾーン全体にできるだけ均等に分散するために spread 配置戦略を選択することになるでしょう。
Amazon ECS と AWS Fargate を併用すると、タスクをアベイラビリティーゾーン全体に分散させることがさらに簡単になります。サービスを作成するとき、または RunTask リクエストにおいて、タスクのネットワーク設定で複数の Amazon VPC サブネットを指定する必要があります。Amazon VPC の各サブネットはそれぞれ単一のアベイラビリティーゾーンにあります。Amazon ECS は、タスクのプロビジョニング中に設定されたサブネットを使用してタスクを起動するアベイラビリティーゾーンを決定し、すべてのワークロードがこれらのサブネットに分散されるようにします。AWS Fargate は、常にサブネットを介してアベイラビリティーゾーン全体にタスクを分散します。この分散は、サービスをデプロイする場合はサービス名、RunTask を介して単一タスクを起動する場合はタスク定義のファミリー名に基づいています。

AWS-Fargate-spread

分散システムにおけるフォールバックの回避

障害の発生を軽減するためにできることはすべて行ったとしても、ある時点で予期しないイベントによってインフラストラクチャまたはソフトウェアに障害が発生することはあり得ます。Jacob Gabrielson は、「分散システムでのフォールバックの回避 」という記事の中で、Amazon が障害に直面した際にフォールバック(障害が起きた際に異なるメカニズムを使用して、同じ結果を達成しようとする考え方)することで、かえって障害を悪化させてしまう可能性を発見したことについて概説しています。これを軽減するために、私たちはアクティブ – アクティブ・ソリューションを好んでおり、障害及び、サービス・アーキテクチャにおけるバイモーダル動作(バイモーダル動作とは、サービスが通常モードと障害モードで異なる動作を示すこと)を回避するように努めています。Jacob が概説しているように、我々の経験ではこれは複雑さとリスクをもたらすものです。
自分達のサービスの可用性を向上させるため、1 つのアベイラビリティーゾーンが失われてもサービスが存続できるように (通常、これは利用可能な容量の 33% に相当します)、事前に十分なスケーリングを行っています。例えばあるサービスにおいて、ある程度の余裕があるピーク時のトラフィック負荷をサポートするために 6 つのワーカーが必要であり、そのサービスが 3 つのアベイラビリティーゾーンでホストされている場合、アベイラビリティーゾーンごとに 3 つのワーカー(つまり、アベイラビリティーゾーン毎にプロビジョニングされるワーカー全体の 50%)をプロビジョニングすることで、合計 9 つのワーカーをプロビジョニングします。これにより、1 つのアベイラビリティーゾーンに障害が発生した場合でも、残りのアベイラビリティーゾーンでは十分に事前にスケーリングされ、ピーク時でもサービスがリクエストを処理し続けるのに必要なキャパシティを確保できます。
Amazon ECS サービスで同じ可用性を実現するには、サービスに必要なタスク数をピーク時のトラフィック負荷よりも 50% 大きくし、3 つのアベイラビリティーゾーンに分散して配置します。デプロイ中、またはスケーリングアクティビティの結果として、Amazon ECS は、設定した配置戦略を確実に反映するようにします。Spread 配置の場合、Amazon ECS は設定したアベイラビリティーゾーンにタスクを分散します。
必要なタスク数を決定するには、次の方法をとることができます。

1) まず、サービスを運用する上で必要なタスクの最大数を決定します。これを「基本希望数」と呼びます。

2) 使用する予定のアベイラビリティーゾーンの数を決定します。これを「AZ スプレッド数」と呼びます。

3) 1 つのアベイラビリティーゾーンが利用できなくなった場合でも、ピーク時のトラフィック量を満たし続けるために必要な追加タスク数を計算します。これを「目標希望数」と呼びます。

これを次のように計算します。
目標希望数 = 基本希望数 X ( AZ スプレッド数 / (AZ スプレッド数 – 1) )
たとえば、6 つのタスクが必要で、AZ が 3 つある場合、次のようになります。
目標希望数 = 6 X ( 3 / ( 3 – 1) ) = 9

Fargate-service-pre-scaled-to-150-

アベイラビリティーゾーンが 3 つ以上あるリージョンで展開されるような大規模なサービスでは、サービスの構成要素をより多くのアベイラビリティーゾーンに分散させることで、1 つのアベイラビリティーゾーンにおいて必要な事前スケーリング規模を削減することができます。これにより、可用性要件を満たしながら、コストを削減できます。たとえば、us-east-1 には 6 つのアベイラビリティーゾーンがあります (2023/12/15 時点)。次の例を見ると、ピーク負荷を処理するために 600 個の Amazon ECS タスクを必要とするサービスに対して、より多くのアベイラビリティーゾーンで均すことのメリットがわかります。

  • 3 つの AZ で 600 件のタスク:目標希望数 = 600 X ( 3 / ( 3 – 1 ) ) = 900
  • 6 つの AZ で 600 件のタスク:目標希望数 = 600 X ( 6 / ( 6 – 1 ) ) = 720

このケースでは、可用性目標を達成しつつより多くのアベイラビリティーゾーンを使用することでコンピューティングコストを節約できることがわかります。50% の追加コンピューティングが必要なのではなく、上記のシナリオでは 20% で同じ結果が得られます。ワークロードの性質によっては、AZ 間のデータ転送料金が増加し、コストが増加する可能性に注意する必要があります。
このアプローチには多くの利点があります。まず、ロードバランサーとロードバランサーのヘルスチェックが正しく設定されていれば、1 つのアベイラビリティーゾーンで障害が発生してもサービスは引き続き稼働します。第二に、Jacob が記事で概説したリスクを確実に軽減することになるため、障害を軽減するためのフォールバックがなくて済みます。第三に、このアプローチはテスト環境や検証環境などにおいて同じ設定で環境を構築し、単一のアベイラビリティーゾーン内のすべてのワーカーノードを強制終了することで、簡単にテストすることができます。

Amazon ECS ではアベイラビリティーゾーンからのトラフィックを除外する方法を標準的な運用手順の一部として使用しており、準本番環境および本番環境で定常的に適用しています。これは、顧客に対する高可用性の義務を果たすための重要な考え方です。

シャーディングによるワークロード分離

Amazon ECS では、シャーディングによるワークロード分離を使用しています。これは、Colm MacCártThaigh の記事「シャッフルシャーディングを使ったワークロードの分離 」で紹介された概念です。これにより、サービスのスケーリングが可能になり、顧客の一連のワークロードを分離する境界を設けることができます。リージョン内の Amazon ECS コントロールプレーンを構成するサービスの中核となるセットは、いわゆるセルに分割されています。各セルは、コントロールプレーンの完全で独立したインスタンスであり、そのリージョンの顧客ワークロードのサブセットを管理します。各セルは前述のように、ピーク負荷容量の 150% 以上で、少なくとも 3 つのアベイラビリティーゾーンにわたってプロビジョニングされます。このセルベースのパーティショニングを使用して、お客様の障害分離をさらに強化しています。顧客のワークロードはリージョン内のセルのサブセットに関連付けられ、それらのワークロードを管理するプロセスは他のセルのプロセスとは異なっています。

ECS-Control-Plane

このアーキテクチャパターンは、規模と可用性の両方に大きなメリットをもたらすことがわかりました。セルはコントロールプレーンの障害分離境界として機能し、アベイラビリティーゾーンはインフラストラクチャの障害分離境界として機能します。ハードウェアまたはソフトウェアの障害が原因で障害が発生した場合、その障害は通常、単一の障害ゾーンとお客様のワークロードの一部に限定されます。このパターンは、スケーリングを検討する際に非常に役立ちます。セルは本番環境全体の比較的小さな単位であると同時に、完全なソリューションでもあるため、テスト環境や検証環境などの非本番環境において単一セルであっても本番環境相当のスケーリングのテストを行うことができます。本番サービスのスケーリング制約を理解するには、1 つのセルに対してスケーリングのテストを実施するだけで済みます。なぜなら 1 つのセルが本番環境全体の小さな単位であり完全なソリューションであることから、その制約を把握することで本番サービスのスケーリング制約を類推することができるためです。
Amazon ECS のお客様は、クラスターとサービスを組み合わせてこれらの障害分離境界を活用することができます。クラスターを作成すると、1 つ以上の Amazon ECS セルに関連付けられます。クラスターにプロビジョニングされたワークロードは、クラスターが配置されているセル内にあるコントロールプレーンセルによって管理されます。

Cell-fault-isolation-boundary

ソリューションを設計する際の考慮事項の 1 つは、1 つ以上のクラスターをプロビジョニングするかどうかです。Amazon ECS クラスターは、ワークロードをグループ化するために使用される論理的な名前空間です。これは、Amazon ECS 内の障害ゾーンとワークロードを関連させるのに役立ちます。1 つ以上のクラスターをプロビジョニングした場合、異なる Amazon ECS クラスターにおいて相関的な障害からの保護が可能になります。Amazon ECS クラスター内のサービスと Amazon EC2 インスタンスのサービスクォータは比較的大きく、リージョンあたり数千のクラスター、クラスターあたり数千の Amazon ECS サービスに対応できることにお気づきかもしれません。クラスターには料金はかかりません。また、同じ Amazon Virtual Private Cloud (Amazon VPC) ネットワークに多くのクラスターを配置できます。ワークロードは同じネットワーク内のクラスタ間で自由に通信できるため、コストをかけずに可用性のニーズに合わせてクラスタを使用することができます。

レジリエンス(回復力)

前述したように、レジリエンス(回復力)とは、悪条件下でも運用を継続できるサービス能力と、通常の運用に戻ることができる速さです。水平方向にスケーリングするワークロードでは、何か障害が発生したとしてもサービスを引き続き利用できるようにしたいと考えています。これは前のセクションで説明したように、事前スケーリングとアベイラビリティーゾーンの静的安定性によって実現されます。回復力の観点からは、サービスができるだけ早く定常状態に戻るようにすると同時に、稼働している状態をできるだけ保ちたいと考えています。

安全なハンズオフ(手放し)デプロイの自動化

AWS では自動化を重視しており、継続的デプロイはこの自動化の重要な部分です。Clare Ligouri は、安全な継続的デプロイを自動化するためのパターンを説明する素晴らしい記事を公開しています。
Amazon ECS は、継続的デプロイによって 1 日に複数回デプロイされます。サービスの変更は、障害発生時の影響範囲 (”Blast Radius : 爆発半径“とも呼ばれます)を緩和するために、1 つの AWS リージョンのアベイラビリティーゾーンに一度に 1 つずつ適用されます。また、サービスの新しいリビジョンがそのアベイラビリティーゾーン内のサーバーセットのごく一部にのみ導入されるような頻度でデプロイメントが管理されるようにします。Clare は記事の中で、これをローリングデプロイと呼んでいます。これは、Amazon ECS がお客様のサービスに対してデフォルトでサポートしているのと同じデプロイ戦略です。デプロイが成功しているかを確認するために、サービスの全体的な状態を追跡し、望ましくない動作をすばやく特定できるメトリクスを使用しています。これらのメトリクスで望ましくない結果が見つかった場合、デプロイは自動的にロールバックされます。同時に、1 つのアベイラビリティーゾーンで検出された障害は、影響を受けたアベイラビリティーゾーンのトラフィックを即座に除外する自動化プロセスによって軽減されます。これは、単一の AZ 障害に対応するための事前スケーリングがすでに実施されているため、お客様に影響を与えることなく実現できます。

自動化された安全なハンズオフデプロイとシャーディングによるワークロードの分離

前述のように、Amazon ECS コントロールプレーンを構成するサービスのコアセットは、セルと呼ぶものに分割されています。サービスの回復力をさらに向上させるため、デプロイは単一のセル内と単一のアベイラビリティーゾーン内で行われます。このアプローチにより、アベイラビリティーゾーンでの事前スケーリングを使用して、障害発生時やワークロードの分離時に AZ を除外し、デプロイから生じる予期しない問題への影響をさらに抑えることができます。その結果、変更は一部のサービスワーカーに少しずつ展開されます。

Core-Services

変更は変更セット(変更を加えられる一塊のグループ)としてリリースされます。新しい変更セットを導入する際には、非常に保守的なアプローチを取っています。徹底的なテストが完了すると、新しい変更セットは、ローリングデプロイ戦略を使用して本番環境に少しずつ導入されます。新しい変更セットは、1 つのアベイラビリティーゾーンと 1 つのセル内の 1 つのリージョンに導入され、一部のワーカーにのみ導入されます。デプロイは自動ロールバックアラームで監視されます。いずれかの時点で悪影響が検出された場合、デプロイはすぐにロールバックされます。私たちは待機時間 (Bake Time : Clare の記事に記載) と初期段階の小さな変更の積み重ねを活用して、変更セットの信頼性を向上させていきます。十分に信頼性が高くなれば、導入のスピードを上げていきます。私たちは、単一の変更セットが、同時に 1 つのリージョンの単一のアベイラビリティーゾーンにのみデプロイされるようにすることに強くこだわっています。
AWS CodePipeline と Amazon ECS を使用すると、同じデプロイパターンをモデル化し、サービスに対して同様のレジリエンス(回復力)を実現できます。

まとめ

この投稿では、Amazon ECS で採用しているレジリエンス(回復力)と可用性の原則をいくつか紹介しました。これらのパターンを使用することで、1 つの AZ に障害が発生した場合でも可用性の高いサービスを提供できると同時に、エンジニアリングチームはソフトウェアを安全かつ継続的に提供できるようになります。これらのパターンについては、この記事全体にわたって参照されている Amazon Builders’ Library のドキュメントで詳しく説明されています。これらのドキュメントが、可用性のニーズを満たすサービスを設計する際に有用なガイドとなることを願っています。
この投稿で説明したパターンを使用することには様々な利点があり、それによって Amazon ECS には予期しない障害に直面したとしても高い可用性と回復力が確保されるようになっています。こうしたパターンを継続的デプロイパイプラインに組み込むことで、障害を軽減するメカニズムの標準化ができます。私たちは、コントロールプレーンをセルに分割するというワークロードの分離テクニックを活用し、少なくとも 3 つのアベイラビリティーゾーンにわたってソリューションを事前にスケーリングしています。この考え方を自動ロールバックアラームを備えたローリングデプロイ戦略と組み合わせることで、サービスの可用性を維持しながら開発者の俊敏性を実現することができます。すべてのサービスがこのレベルの可用性や俊敏性を実現する必要があるわけではないため、場合によりこれらのパターンは適切ではないケースもあります。高可用性と回復力の目標を達成する必要がある、大規模で成長過程にあるサービスには、この投稿で紹介した方法論はうまく機能するでしょう。このトピックの詳細については、re: Invent 2023 のセッション “Deep dive into Amazon ECS resilience and availability (CON401)“を参照ください。

翻訳はパートナーソリューションアーキテクトの髙橋達矢が担当しました。原文はこちらです。