Amazon Web Services ブログ

詳解: Amazon ECS による CPU とメモリのリソース管理

この記事は How Amazon ECS manages CPU and memory resources (記事公開日: 2019 年 10 月 21 日) を翻訳したものです。

2019 年 8 月 19 日に、コンテナ単位で Linux 上で使用可能なスワップ領域の設定をサポートする Amazon Elastic Container Service (Amazon ECS) の新機能を発表しました。この機会を利用して、ECS のリソース管理がどのように機能するかについて (この新機能によって導入された動作も含めて) 、一歩下がってより全体的な説明をしたいと思います。具体的には、ECS によってさまざまな起動タイプ (すなわち、Amazon EC2AWS Fargate) にデプロイされた Linux コンテナによって、CPUとメモリのリソースがどのように予約され、使用されるかを明確にします。なお、Windows コンテナは、ECS でサポートされていますが、このブログ記事のスコープ外です。

ECS の構成要素

ECS では、デプロイの基本単位はタスクであり、タスクは 1 つまたは複数のコンテナをモデル化する論理的な構成要素です。つまり、ECS の API は、個々のコンテナではなく、タスクに対して動作します。ECS では、コンテナを直接実行するのではなく、その代わりにタスクを実行し、タスクがコンテナを実行します。タスクには、1 つまたは複数のコンテナが含まれています。

次の図は、コンテナとタスクの関係の概要を示しています。

ECS におけるコンテナとタスクの関係を示す図です。タスク 1 からタスク 4 までの 4 つのタスクが示されている。各タスクを示すボックスがあり、ボックスの中に 2 つのコンテナがあります。

ECS の公式ドキュメントには、これらの構成要素についての詳細が記載されています。

このブログ記事の目的は、リソース管理に関してどのようなオプションがあるのか (そして、どのようなルールに対応しなければならないのか) を説明することです。特に、タスクレベルやコンテナレベルで定義された CPU や メモリのリソースが、EC2 や Fargate で使用可能な CPUメモリのリソースとどのように関係するのかについて説明します。

利用可能な ECS 起動タイプの紹介

ECS には、コンテナを実行するための 2 つの異なるモデルがあり、これを起動タイプと呼びます。1 つ目は、お客様が所有および管理し、料金を支払う EC2 インスタンス上で ECS タスクを実行する方法で、タスクごとの支払いは必要ありません。2 つ目は、AWS によって完全に管理されるコンテナ用のサーバーレス環境である Fargate を使用する方法で、お客様は基盤となるインフラストラクチャを管理することなくコンテナを実行できます。Fargate では、お客様は実行したタスクに対してのみ課金されます。

以下の図は、EC2 起動タイプでタスクを起動したときに何が起こるかを視覚的に示しています。

EC2 起動タイプで ECS タスクを起動する際のインタラクションを示した図です。3 つのボックスが示されています。真ん中のボックスには「aws ecs run task ... --launch-type EC2 ...」というテキストがあり、左側のボックスには「AWS」というラベルと「Amazon ECS」という小さなボックスがあり、矢印が描かれています。最初のボックスの下に、左側のボックスから始まり、右側のボックスの中に終わる矢印が描かれています。右側のボックスは「Cust Account」と表示され、いくつかの小さなボックスが含まれています。1 つは「Amazon EC2」とラベル付けされ、矢印はこのボックスを指し、「この容量を管理する必要があります (例えば ASG を使用して) 」とラベル付けされています。「Amazon EC2」ボックスの上には、「Service」と「Task」というラベルが付いた色のついた領域があり、起動した Amazon ECS のタスクを表しています。

以下の図は、Fargate 起動タイプでタスクを起動したときに何が起こるかを視覚的に示しています。

ECS タスクを Fargate 起動タイプで起動する際のインタラクションを示した図です。3 つのボックスが示されています。真ん中のボックスには「aws ecs run-task ... --launch-type FARGATE ...」というテキストがあり、「AWS」と書かれた左側のボックスへ矢印が描かれています。左側のボックスには、「Amazon ECS」と「AWS Fargate」と書かれた小さなボックスと、AWS Fargate のボックスの真上に置かれた「Service」と「Task」というラベルを含む色のついたエリアがあります。Amazon ECS のボックスから、「Service」と「Task」のラベルが付いた色の付いた領域に矢印が描かれています。「Task」ラベルから、「Cust Account」と書かれた右側のボックスと、「ENI」と書かれたボックス内の要素に矢印が引かれています。

このブログ記事の文脈で考慮すべき重要な点の 1 つは、「各 Fargate タスクは、独自の分離境界を持ち、基盤となるカーネル、CPU リソース、メモリリソース、Elastic Network Interface を別のタスクと共有しません。」 という点です。つまり、EC2 起動タイプでは同じ Linux カーネルの上で複数のタスクが動作し、互いにカーネルリソースを共有できますが、Fargate 起動タイプでは各タスクが専用の Linux カーネルを持ち、他のタスクと CPU やメモリ、ENI (Elastic Network Interface) を共有しません。2 つの異なる起動タイプの全体的な比較はこのブログ記事のスコープ外ですが、これらの起動タイプのどちらを使用するかは、CPU とメモリのリソースをコンテナで予約および使用する方法に多くの影響があります。

コンテナの一般的な背景およびコンテナが CPU とメモリにアクセスする方法

ECS がどのように機能するかの説明に入る前に、コンテナのデフォルトの動作から一般的に期待されることについて、少し時間をとって説明しましょう。

コンテナには 2 つの一般的なおおまかなルールがあります。

  • 特に制限や上限を設けない限り、あるホスト (OS) 上で起動したコンテナは、そのホスト上で利用可能なすべての CPU とメモリ容量にアクセスできます。
  • 特に保護や保証されていない限り、あるホスト (OS) 上で実行されているすべてのコンテナは、そのホスト上で動作する他のプロセスと同じように CPU、メモリおよびその他のリソースを共有します。

これらの動作は、コンテナに特有の動作ではなく、むしろ Linux プロセス一般にとって普通であり期待される動作です。デフォルトでは、CPU やメモリなどのリソースへのアクセスに関して、コンテナは他の Linux プロセスと同じように動作することを強調しておく必要があります。

ECS のリソース管理オプション

このブログ記事を通して、ECS が提供する以下のような容量の制限と予約の仕組みを学びます。

  • ECS はタスク (およびそのコンテナ) があるホスト上で使用できる容量を制限するだけでなく、タスク (およびそのコンテナ) が使用可能であると期待する容量を予約する仕組みを提供します。
  • ECS はコンテナがタスク内で使用できる容量を制限するだけでなく、コンテナが使用可能であると期待する容量を予約する仕組みを提供します。

ECS を初めて使用する方のために、1 つのコンテナを含むタスク定義の例を以下に示します。タスク定義は、実行するコンテナを定義する ECS の構成要素であると考えることができます。register-task-definition のドキュメントを見ると、タスク定義のオプションが豊富で幅広いことに気付くでしょう。この短い例では、タスクとコンテナを設定する方法のうち、リソース管理の側面にフォーカスし、他の多くのオプションは割愛しました。 また、この例は EC2 起動タイプとのみ互換性があることにも気付くでしょう。これは、一部の CPU とメモリの設定 (具体的には maxSwapswappiness) が Fargate 起動タイプではサポートされていないためです。

{
    "family": "mywebsite", 
    "networkMode": "awsvpc",
    "cpu": "256", 
    "memory": "512", 
    "requiresCompatibilities": ["EC2"],  
    "containerDefinitions": [
        {
            "name": "mywebsite-nginx", 
            "image": "nginx:latest", 
            "essential": true,
            "cpu": 128,
            "memory": 256,
            "memoryReservation": 128,
            "linuxParameters": {
                "maxSwap": 512,
                "swappiness": 50
            }
        } 
    ]
}

このタスク定義は、以下のコマンドを実行して登録できます (mywebsite.json は、上記の JSON を含むローカルディレクトリ内のファイルです) 。

aws ecs register-task-definition --cli-input-json file://mywebsite.json

上記の JSON 構造は、次のことを行っています。

  • mywebsite という ECS タスクを定義しています。このタスクには、一定量の CPU とメモリ容量が関連付けられています (起動する EC2 インスタンス上で 256 CPU ユニットと 512 MiB のメモリを予約します) 。もしこの定義が Fargate 起動タイプで起動されるとしたら、これらの値はタスク実行時に適切なサイズの Linux インスタンスを決定するために使用されます。
  • タスク内に mywebsite-nginx という 1 つのコンテナを定義しています。このコンテナには、128 CPU ユニットと 256 MiB のメモリが関連付けられており、128 MiB が予約されています。これに加えて、今回発表した新機能では、設定可能なパラメータが追加されており、最大スワップサイズ 512 MiB を、標準的な積極性 (swappiness は 0 から 100 の整数を受け付けます) で設定しています。

この設定は説明のみを目的としており、使用した値には、使用可能なオプションを示す以外の特定の意味はありません。このブログ記事の残りの部分では、これらのオプションやパラメータの使用方法と、タスクやコンテナレベルでそれらを使用した場合に何が起こるかを説明します。

これらのパラメータを使用するときに自由に使用できるさまざまなオプションを説明するために、2 つのシナリオを説明します。

  • 柔軟性を最大化する: このアプローチは、オプション設定の数を最小限に抑え、リソースのオーバーコミットを最高レベルにし、上で述べたデフォルトのコンテナ体験に最も近づけることを目標とする場合に使用できます。パフォーマンスよりもコストを最適化したいテスト/デバッグ環境では、このアプローチを検討するとよいでしょう。
  • 制御を最大化する: このアプローチは、タスクとコンテナの両方のレベルで、最高レベルのパフォーマンス予測可能性と、リソースの上限と予約に関して最高レベルの微調整を行うことを目標とする場合に使用できます。コストよりもパフォーマンスを最適化したい機密性の高い本番環境では、このアプローチを検討するとよいでしょう。

あなたの具体的なユースケースは、この 2 つの極端なアプローチのいずれかに当てはまるかもしれませんし、その中間に位置する可能性もあります。たとえば、本番運用中のワークロードにある程度のオーバーコミットを与えて、リソース需要の突然の短いピークに対応できるようにしたいと考えるかもしれません。

このブログ記事は、具体的なユースケースに合わせてタスクとコンテナの設定を微調整するための、すべての基本的な方法を提供することを目的としています。

柔軟性を最大化する

最も制限のない柔軟なアプローチは、特定の CPU とメモリリソースの設定を持たないタスクを使用することです。

この場合、これらのタスクは以下のようになります。

  • EC2 コンテナインスタンスにのみデプロイできます (Fargate はタスクに特定の CPU とメモリリソースの設定を必要とします) 。
  • 少なくともメモリのソフト制限またはハード制限のどちらかを持つコンテナが必要です。
  • コンテナの CPU リソースは設定する必要ありません (コンテナはホスト CPU のフルパワーを求めて競合します) 。

注: コンテナに CPU ユニットを指定しない場合、ECS は内部的に cgroup に対して 2 (Linux カーネルが許容する最小値) という値の Linux CPU 配分 (cpu.shares) を設定します。「CPU ユニット」は、ECS の構成要素であり、Linux カーネルの世界には存在しないことに注意してください。CPU ユニットが (Linux CPU 配分と cgroup 設定を介して) Linux ホストで強制される方法については、実装の詳細でありここでは触れません。また、Linux は CPU の数や、定義する配分の絶対値を気にしないことに注意してください。Linux は、CPU 競合時に特定の cgroup が利用できる CPU リソースの割合を決定する際に、階層内の特定の場所で定義されたすべての CPU 配分の合計を分母として使用します。

やや柔軟性の低いアプローチは、特定の CPU やメモリリソースの設定を持つタスクを使用することです。このアプローチはいくつかのタスクのリソース設定を想定していますが、コンテナレベルでは優れた設定不要の体験を可能にします。

この場合、実際のところ、これらのタスクは以下のようになります。

  • EC2 コンテナインスタンスまたは Fargate にデプロイできます。
  • メモリ (または CPU) の制限が全く設定されていないコンテナを持つことができます。

この図は、最低限必要な設定オプションを示したものです。

さまざまな状況下で使用可能なオプションを示した図です。上部に「タスク」と書かれた箱があり、その中に「コンテナ」と書かれた 2 つ目の箱があります。左右に分岐しているのは、「サイズ設定なしのタスク」と「サイズ設定ありのタスク」と書かれた矢印です。「サイズ設定なしのタスク」と書かれた矢印では、「Amazon ECS」と書かれたボックスのみが起動可能で、コンテナメモリは必須、コンテナ CPU、タスクメモリ、およびタスク CPU はオプションと記述されています。「サイズ設定ありのタスク」と書かれた矢印の場合、「Amazon EC2」と「AWS Fargate」の両方が含まれ、タスクメモリとタスク CPU は必須、コンテナメモリとコンテナ CPU はオプションとして記述されています。

この図は、ECS ユーザーが検討する必要がある、リソース使用量の最大レベルの柔軟性 (または、必要な場合は最小レベルの設定) を説明することを目的としています。

Fargate のデプロイメントでタスクの CPU とメモリの設定が必要な理由は、Fargate の課金対象の構成要素であるためです (EC2 インスタンスではなく、タスクの実行に必要なコンピューティング容量の料金を支払います) 。前述したように、各タスクは専用の Linux カーネルを持っているので、タスクサイズは適切な物理リソースを割り当てるためにも使用されます。

最も柔軟性の高いアプローチ (タスクサイズ設定なし) には、ユーザーがリソースの分配を制御できないという欠点があります (すべてのタスクとコンテナが EC2 コンテナインスタンスのホスト上で同じリソースを求めて競合します) 。しかし、このアプローチの利点は、ユーザーが (EC2 コンテナインスタンス上で) オーバーコミット戦略を実装できることであり、特定のシナリオでは大幅な節約が可能になります。

もう 1 つのアプローチ (タスクサイズ設定あり) は、コンテナレベルで設定するパラメータが 1 つも必要ないため、ある程度柔軟性があります。ただし、コンテナはタスク内のリソースをオーバーコミットすることができますが、タスク自体はホスト上のリソースをオーバーコミットすることはできません。これについては、次のセクションで詳しく説明します。

制御を最大化する

ECS では、コンピューティングリソース (CPU やメモリなど) をタスクやコンテナに割り当てる方法について、より詳細に制御することもできます。

このセクションでは、これらのリソースを微調整する方法と、それに関連する影響について説明します。前のセクションとの一貫性を保つために、このセクションをいくつかの異なるサブセクションに分割します。

  • タスクサイズを設定しないと何が起こるか (EC2 起動タイプのみで使用可能な設定)
  • タスクサイズを設定すると何が起こるか (EC2 と Fargate の両方の起動タイプで使用可能な設定)
タスクサイズ設定なし タスクサイズ設定あり
EC2 起動タイプで使用できるか はい はい
Fargate 起動タイプでしようできるか いいえ はい

注: タスクサイズは部分的に設定する (たとえば、メモリサイズは設定するが CPU サイズは設定しない) ことも可能ですが、簡略化するために、以下の議論では、両方を設定するか、何も設定しないことを想定します。以下の 2 つのシナリオを合わせて考えることで、1 つだけを設定した場合に何が起こるかを簡単に推定することができます。

1 – タスクサイズを設定しない場合のコンテナのリソース設定

これは、ECS が歴史的に機能してきた方法です。注意点として、この設定は Fargate 起動タイプではサポートされていません (すなわち、タスクのサイズを設定しない場合は Fargate を使用することができません) 。そのため、この構成は EC2 起動タイプでのみ使用可能です。

このシナリオでは、タスクは単なる制限のない論理的な境界であり、リソースに関する設定はすべて、(すべてのタスクをまたがった) 個々のコンテナの設定と、EC2 コンテナインスタンスレベルで利用可能な物理的容量に関係します。

前のセクションで示唆したように、このようなタスクで実行されるコンテナには、少なくともソフトメモリ制限またはハードメモリ制限のいずれかが必要です。

ソフトメモリ制限を設定すると、基本的に、タスクが実行されるホストのメモリ容量が予約されます。言うまでもなく、ある EC2 インスタンスで実行されているすべてのタスクのすべてのコンテナのソフトメモリ制限の合計は、そのインスタンスで利用可能な物理メモリを超えることはできません。メモリを予約しているので、タスク (とコンテナ) が起動できるように、(実際の使用量に関係なく) そのすべてのメモリが利用可能である必要があります。これは物理メモリのみであり、最近発表した新しい maxSwap オプションで設定した追加のスワップスペースではないことに注意してください。この新機能では、適切に設定されていればコンテナがスワップできるようになりますが、スケジューリングフェーズではスワップ使用量の考慮は行われません。スワップは、ECS スケジューラのリソースとしては扱われません。

注: 新しいスワップ機能を使用する場合は、使用する EC2 インスタンスでスワップ機能を有効にしてください。ECS に最適化された AMI では、デフォルトでスワップは有効になっていません。この新機能を使用する際の考慮事項の完全なリストについては、ドキュメントを参照してください。

ハードメモリ制限を設定すると、コンテナに上限を設定することになります。つまり、コンテナはその量以上のメモリを使用できません (「メモリが必要になったとしても、とにかくこの値を超えることはできません」) 。メモリサイズが設定されていないタスクは、たとえホスト上で利用可能なメモリ量を超えるハードメモリ制限を持つコンテナを含んでいたとしても、ECS スケジューラによってスケジュールされ起動されます。(訳注: ソフトメモリ制限を設定した場合に限ります。ソフトメモリ制限を設定しない場合には、ハードメモリ制限がメモリ予約に使用されるため、タスクはスケジューリングされません。) このとき、タスク実行時における正味のメモリ上限は、タスクで設定したハードメモリ制限ではなく、ホスト上で利用可能なメモリとなります。

以下は、利用できるすべてのオプションと、そのうちの 1 つを選ぶとどうなるかです。

  • ソフト制限のみを設定した場合、それは予約を表し、上限はコンテナインスタンスの合計メモリ量で表されます。
  • ソフト制限とハード制限を両方設定した場合、ソフト制限は予約を表し、ハード制限は上限を表します。
  • ハード制限のみを設定した場合、それは予約と上限の両方を表します。

コンテナがこの 2 つの値の間 (ハード制限が設定されていない場合は、ソフト制限とホスト容量の間) でメモリを使用しようとすると、コンテナは互いに競合する可能性があります。この場合、何が起こるかは、Linux カーネルの OOM (Out of Memory) Killer が使用するヒューリスティックに依存します。ここでは ECS と Docker はどちらも関与しておらず、Linux カーネルがメモリの圧迫に反応しているだけです。ソフト制限を超えているものは、ソフト制限を下回っているものよりも強制終了される可能性が高いのですが、どのプロセスが強制終了されるかを判断するには、システム上の他のすべてのプロセスと、それらのプロセスがメモリに対して何を行っているかを知る必要があります。ここでも、今回発表した新しいメモリ機能が役に立ちます。OOM の動作は変わりませんが、メモリ不足のシナリオではディスクにスワップするようにコンテナを設定できるようになりました。これにより、OOM Killer が発動する必要性を軽減できる可能性があります (コンテナがスワップするように設定されている場合) 。

CPU リソースの場合、仕組みは少し異なります。ECS では、CPU をメモリのソフト制限の動作に似た「CPU ユニット数」で設定することができます。ベースラインとして、ECS は EC2 コンテナインスタンスが利用できる各 vCPU を 1024 ユニットと見なします。つまり、8 個の vCPU を持つ EC2 ホストは、8 × 1024 = 8192 CPU ユニットが利用可能です。コンテナに CPU ユニットを割り当てると、基本的にホスト上でその容量を予約することになります。言うまでもなく、EC2 インスタンス上で実行されているすべてのタスクのすべてのコンテナの CPU ユニットの合計は、そのホストで利用できるユニットの総数 (上記の例では 8192) を超えることはできません。すでに上で述べたように、この ECS の用語の CPU ユニットは、Linux の CPU 配分として適用され、動作を強制されます。言い換えれば、「ユニット」は ECS が動作を設定するために使用する用語であり、「配分 (share) 」は Linux カーネルがそれを実装するために使用するテクノロジーです。ほとんどの ECS ユーザーにとって、これは気にする必要のない詳細ですが、明確にしておくことが重要です。

とは言え、ここでは考慮すべきことがいくつかあります。

  • コンテナが割り当てられた CPU ユニットを使用していない場合、他のコンテナはその容量を使用できます。容量が使用されていない場合、どのコンテナもバーストしてその空き容量を使用できます。CPU 配分は、複数のコンテナが同時に CPU を使用しようとする CPU 競合が発生した場合に、使用可能な CPU 容量の量を制御します。
  • ホストに空き容量がある場合 (すべてのタスクのすべてのコンテナの CPU ユニットの合計がホストの利用可能な容量より小さいため) 、ホストの余剰容量は、コンテナがそれを必要とする場合に、すべてのコンテナに比例して再分割されます。

たとえば、8192 CPU ユニットを持つホストでタスクを実行する場合を考えてみましょう。このタスクには、コンテナ A (512 ユニットを割り当て) と コンテナ B (1024 ユニットを割り当て) の 2 つのコンテナがあります。両方のコンテナがフル稼働して予約された容量を使用している場合、コンテナはコミットされてない CPU パワー (8192 – 512 – 1024 = 6656 CPU ユニット) にアクセスできます。この容量の分割方法は、コンテナに割り当てられたユニットに比例します (つまり、ユニットは重みとして機能すると考えることができます) 。具体的には、コンテナ B は、コンテナ A (6656 の 1/3 = 2219 CPUユニット) に対して 2 倍の CPU ユニット (6656 の 2/3 = 4437 CPU ユニット) にアクセスすることができます。

2 – タスクサイズを明示的に設定する場合のコンテナのリソース設定

この設定は、EC2 起動タイプと Fargate 起動タイプの両方でサポートされています。

この特定のシナリオでは、タスク自体が、そのタスクの内部で実行されるコンテナを囲む強固な境界となります。

このシナリオでは、このタスク設定で実行されているコンテナは、タスクサイズによって定義された容量のみを使用できます。つまり、コンテナはタスクを境界と見なします。 正確には、コンテナは /proc を読み取ることができるため、総容量を見ることはできますが、その総容量はコンテナには使用できません。

メモリ管理の観点から、重要な違いは、コンテナにどのタイプのメモリ制限も設定する必要がないことです。 この場合、コンテナはタスクレベルで使用可能なメモリ量をめぐって競合します。ただし、コンテナレベルでメモリリソースを調整しない場合です。おそらく、コンテナレベルでメモリリソースの調整は、個別のコンテナに至るまでリソースを完全に制御する必要があるようなシナリオでは、実施したい、あるいは必要とされることでしょう。これは、ECS では間違いなく可能です。

コンテナレベルで制限を設定した場合、この特定のタスク内で実行されているすべてのコンテナのメモリソフト制限の合計は、タスクのメモリサイズを超えることはできません。メモリサイズのないタスクとメモリサイズのあるタスクの顕著な違いは、後者のシナリオ (メモリサイズのあるタスク) では、どのコンテナにもタスクのメモリサイズを超えるメモリハード制限を設定できないことです (ただし、すべてのハード制限の合計はタスクのメモリサイズを超えることができ、すべてのソフト制限の合計はタスクのメモリサイズを超えることができません) 。これは、スケジューラがメモリ容量の少ない EC2 ホストにスケジューリングできる前者のシナリオ (メモリサイズのないタスク) とは異なります。

以下は、利用できるすべてのオプションと、そのうちの 1 つを選ぶとどうなるかです。

  • ソフト制限のみを設定した場合、それは予約を表し、上限はタスクメモリサイズで表されます。
  • ソフト制限とハード制限を両方設定した場合、ソフト制限は予約を表し、ハード制限は上限を表します。
  • ハード制限のみを設定した場合、それは予約と上限の両方を表します。

CPU リソース管理の観点からも、アルゴリズムは前のセクションで説明したものと似ていますが、CPU ユニットの総数が EC2 ホスト全体ではなく、設定したタスクサイズになる点が大きく異なります。つまり、タスクサイズを 1024 CPU ユニットに設定すると、そのタスクで動作するすべてのコンテナの CPU ユニットの合計は 1024 を超えることができず、1024 のうち割り当て外の容量は、すでに割り当てられているユニット数に比例してすべてのコンテナに再分配されます。

また、ECS では CPU ユニットをコンテナだけでなくタスクに割り当てる CPU 容量の量として参照しますが、それらが適用される方法は異なることを理解することも重要です。タスクに割り当てられた CPU ユニットは、Linux カーネルによってタスクの CPU のハード上限として強制されます (実際、このタスクで動作するコンテナは、タスクに割り当てられた制限を超えることはできません) 。一方、コンテナに割り当てられた CPU ユニットは、タスク内の Linux CPU 配分を使って実装されます (これは、むしろ CPU アクセスの優先度を決定するための、重み付けメカニズムです) 。

注: このブログ記事の執筆時点では、タスクレベルでの CPU ユニットの割り当ては 10 vCPU (10240 CPU ユニット) を超えることはできません。つまり、コンテナで 10 vCPU 以上を使用したい場合は、CPU タスクサイズを設定しないでください。

すべてのオプションを理解する

以下の表は、上で説明した「タスクサイズが設定されていないタスク」と「タスクサイズが設定されているタスク」の 2 つのシナリオにおける、タスクとコンテナの両方の特性と動作を要約したものです。

タスクサイズ設定なし タスクサイズ設定あり
タスクの動作
EC2 起動タイプで使用できるか はい はい
Fargate 起動タイプで使用できるか いいえ はい
タスクにリソース予約はあるか いいえ はい (タスクサイズを予約する)
タスクにリソース上限はあるか いいえ (ホストのサイズに制限される) はい (タスクサイズに制限される)
コンテナの設定オプション (タスク内)
コンテナが使用可能な CPU 容量 (空いている場合) ホストの CPU 容量 タスクサイズ
コンテナが使用可能なメモリ容量 (空いていて、制限されていない場合) ホストのメモリ タスクサイズ
コンテナに CPU 設定は必要か いいえ いいえ
コンテナにメモリ設定は必要か はい (ソフト制限またはハード制限のどちらか) いいえ

アプリケーションのスケジューリングとパフォーマンス

これまで、利用可能なさまざまなオプションのパラメータを調整することによる技術的な影響について、重点をおいて説明してきました。しかし、私たちが行うことはすべて、組織にとって適切なコストで最高のアプリケーションパフォーマンス体験を提供することであるという事実を見失わないようにしなければなりません。パフォーマンスとコストは、私たちの Well-Architected Framework の 2 本の柱です。

アプリケーションの実行には CPU とメモリのリソースが必要です。これまで議論してきたことはすべて、ECS で動作するコンテナ化されたアプリケーションにこれらのリソースを提供する方法を説明しています。また、これまで議論してきたパラメータは、ECS がスケジューリングを決定するための手段にもなります。

Fargate 起動タイプを使用する場合、このスケジューリングのメカニズムは最小限で、簡素化されています。各タスクは、ECS タスクに設定された容量と (少なくとも) 同じ容量を持つ専用の Linux カーネル上でスケジュールされるためです。また、Fargate 起動タイプではメモリスワップ機能が使用できないため、最終的に Fargate タスク内で動作するアプリケーションには、タスクレベルで定義された通りの CPU とメモリ容量があります。

EC2 起動タイプを使用する場合、スケジューリングのメカニズムは ECS によって最大限に発揮されます。これを説明する最もよい方法は、このプロセスが「テトリス」の動作に似ていると想像することです。スケジューリングされていない多数のタスクが落ちてきて、ECS はそのタスク特性に基づいて、これらの「ブロック」を着陸させるために利用できる (CPU とメモリの)「スロット」に従って EC2 インスタンス上で実行するようにスケジュールされます。

具体的には、すべてのブロックの形状とサイズは、タスクやその中のコンテナに関連付けられた予約によって決定されます。考えてみれば、予約は「このタスクにはこれだけのメモリと CPU が必要です」と ECS に効果的に伝えており、ECS はその要求を満たすために、ECS クラスターの 1 つの EC2 インスタンスで十分な予約容量を見つける必要があります。このブログ記事でこれまで説明してきたように、タスクの CPU サイズ、タスクのメモリサイズ、コンテナメモリのソフト制限は、「ブロック」の形状と全体のサイズを形成するのに役立ちます。コンテナのメモリハード制限とコンテナの CPU サイズは、ブロックの形状とサイズを形成する役割を果たしません。これらは、競合が発生した場合の上限または優先順位を示すだけで、(予約のように) 満たす必要のある強力なリソース要件を設定することはありません。(訳注: タスクの CPU サイズを設定しない場合、コンテナの CPU サイズが予約に使用されます。タスクのメモリサイズとコンテナのソフトメモリ制限をいずれも設定しない場合、コンテナのハードメモリ制限が予約に使用されます。)

最終的には、これらのパラメータと 2019 年 8 月に発表したスワップ機能によって、ユーザーはアプリケーション要件により適した方法でブロック (あるいはタスク) を形成することができるようになります。

  • アプリケーションに最大限の予測可能なパフォーマンスが必要な場合は、利用可能なパラメータを使用してタスクの適切な形状とサイズを定義し、ECS スケジューラが特定の形状とサイズのブロックを収容できる EC2 インスタンスを見つけ出すようにします。スケジューラが十分な容量を見つけられない場合、タスクをスケジュールできない可能性があります (適切に設定されている場合、これによってオートスケールイベントがトリガーされる可能性があります) 。
  • アプリケーションがスケジュールされる必要があり、予測可能なパフォーマンスについて心配する必要がない場合、またはコストを最適化しようとしている場合、ブロックの形状とサイズをできるだけ小さくして、上限と配分を使用して優先順位を付けます。ここで実質的に行っているのは、ECS が EC2 インスタンスのスロットにこれらのブロックを簡単に割り当てることができるように、EC2 リソースをオーバーコミットすることです。しかし、アプリケーションが実際に使用し、要求する量よりも予約が少ないため、これらのタスクは EC2 ホスト上でリソースをめぐって競合する可能性があります。この場合、アプリケーションのパフォーマンスが低下したり、メモリ不足で EC2 カーネルに強制終了されたりする可能性が高くなります。このような場合、スワップ機能によってディスクをメモリ領域として使用することで、この重大なイベントを軽減することができ可能性があります。このとき、アプリケーションの速度は次第に低下する可能性がありますが、十分な仮想メモリがあれば強制終了されることはありません。

最終的な分析では、これらすべての構成オプションを使用して、パフォーマンスまたはコストのいずれか (またはそれらの組み合わせ) でアプリケーションのデプロイメントを最適化することができます。 EC2 起動タイプを使用している ECS のお客様は、組織のニーズにより適したデプロイ戦略を見つける責任を負っています。

[2020 年 12 月 11 日更新] アプリケーションの中には、コンテナを認識して、コンテナ内で利用可能なリソースを最大限に活用するように自分自身を構成できるものがあります。Java の最新バージョンは、このパターンの良い例です。このため、これらのアプリケーションの中には、タスクレベルでの設定に加えて、コンテナレベルで CPU とメモリのリソースが明示的に設定されている場合に、最適に動作するものがあります。つまり、特定のリソース設定を持たないコンテナは、名目上すべてのタスクリソースにアクセスできますが、一部のアプリケーションはこの設定を異なって解釈し、コンテナが利用できると考えるリソース量を人工的に制限する可能性があります

まとめ

このブログ記事では、現在利用可能なすべての起動タイプ (EC2 および Fargate) で、リソース管理 (特に CPU とメモリについて) が ECS でどのように機能するかをまとめる機会を得ました。この文脈での新機能の導入は、AWS の ECS への投資と、お客様の声に耳を傾ける姿勢の証です。

ここでは、ECS の基本について説明し、コンテナが Linux ホスト上で CPU やメモリのリソースをどのように使用するかの基本概念について説明しました。そして、これらのリソースを設定するための ECS 固有のアプローチにズームインしました。

いくつかの異なる設定シナリオを紹介しました。1 つはテストや開発向けのユースケース (柔軟性とリソースのオーバーコミットが重要) で、もう 1 つは本番ワークロード (パフォーマンスと予測可能性が重要) をターゲットとしたものです。

2 つのシナリオのそれぞれについて、多数の設定オプションと代替案を考慮し、タスクの設定に焦点を当て、次にコンテナの設定オプションにズームインしました。全体として、このドキュメントの構成は、ユーザーが特定のユースケースと要件に適したアドホックのタスクとコンテナの設定戦略を実装するための、低レベルの情報のほとんどを提供できていると考えています。

技術的な要点は以下の通りです。

EC2 インスタンス上に ECS タスクをデプロイすることで、最高レベルの柔軟性が得られます。

  • タスクサイズの設定があるタスクと、タスクサイズの設定がないタスク (またはそれらの組み合わせ) の両方をデプロイできます。
  • 異なるタスク間でコンテナが同じ物理リソースを共有できるため、リソースをオーバーコミットできます。
  • タスクサイズが設定された (したがって上限がある) タスク 内のコンテナは、このタスクの上限を超えて容量をバーストすることはできません。
  • タスクサイズが設定されていない (したがって上限がない) タスク内の明示的な制限のないコンテナは、他のタスクからリソースを奪って容量をバーストすることができます。これは、それらの他のタスクにサイズが設定されている場合でも、それらのタスクがその容量を利用していない場合は当てはまります。
  • タスクサイズ設定なしまたは非常に小さなサイズのいずれかで、非常に小さなタスク (バースト可能) をデプロイできます (タスクのサイズに関する追加情報は、このリンクを確認してください) 。

Fargate 上に ECS タスクをデプロイすると、柔軟性がやや低下します。

  • 決められたサイズからタスクをデプロイします (その容量の EC2 インスタンスと 1 対 1 でマッピングされます) 。
  • タスクには特定のサイズが設定され、専用の Linux カーネルで実行されるため、異なるタスク間でリソースをオーバーコミットすることはできません (ただし、タスク内でコンテナ間のリソースをオーバーコミットすることは可能です) 。
  • 0.25 vCPU および 512 MiB メモリよりも小さいタスクを作成することはできません。

言うまでもなく、Fargate のお客様にとっての価値は、単なるリソース管理オプションをはるかに超えるものです。Fargate はコンテナのためのサーバーレス環境であり、お客様はコンピューティング能力の管理という差別化につながらない重労働に時間を費やす代わりに、ビジネスニーズに集中することができます。これに加えて、Fargate を使用することで、Linux カーネルをあるタスク専用にすることができ、セキュリティ体制を向上させることができます。

翻訳はプロフェッショナルサービスの杉田が担当しました。原文はこちらです。