Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

【R&D DevOps通信】Amazon ECSのTips

こんにちは、R&D Architectグループの辻田です。ECS on EC2のアーキテクチャでサービスを構築する機会があったので、そこで得た知見をTips形式でまとめたいと思います。

EC2 or Fargate

ECSはEC2とFargateの2つの起動タイプをサポートしていますが、今回はサービスの背景やユースケースの観点からすべてのタスクをEC2で起動することになりました。

EC2 or Fargateはそれぞれメリットデメリットがあり、どちらが最適かはユースケースによって様々です。ざっくり判断基準を上げると

  • EC2インスタンスのスペックやOS、ミドルウェアなど細かいカスタマイズが必要か
  • EC2インスタンスの継続的な管理が可能か
  • リソース使用量が予測でき、最適なインスタンスタイプを選定できるか

などが大切なポイントになると思います。 例えば、新規サービスなどでどれくらいの負荷がくるか予測できない、インスタンスの管理に時間をかけたくない、のような状況ですと、Fargate起動タイプのほうが料金も運用コストも削減できると判断できます。

詳細なコスト比較については以下のAWSの記事で丁寧に書かれてるので参照ください。

Amazon ECS Fargate/EC2 起動タイプでの理論的なコスト最適化手法 | Amazon Web Services ブログ

タスク定義

タスク定義とコンテナ定義

ECSではタスクレベルとコンテナレベルで起動に必要な設定を定義することができます。

タスク定義にはタスクを実行するIAMロール、ネットワークモード、起動タイプ、複数のコンテナ定義の紐付けなどを記述できます。 コンテナ定義はタスク起動時にDockerコンテナに渡すパラメータを記述できます。

それぞれのパラメータはEC2、Fargateで必須項目などが異なるので、詳細については下記ドキュメントを参照ください。

タスク定義パラメータ - Amazon Elastic Container Service

リソース割り当て

タスク定義、コンテナ定義ではCPUとメモリの割り当てを設定することができます。以下の表にそれぞれの違いをまとめてみました。

説明 EC2 Fargate
タスクレベルのCPU タスクに適用されるCPUのハード制限 任意 必須
タスクレベルのメモリ タスクに適用されるメモリのハード制限 任意 必須
コンテナレベルのCPU コンテナ用に予約するCPU Units
コンテナレベルのCPU合計量≦タスクレベルのCPU
必須
タスクレベルでCPUを指定している場合、コンテナレベルのCPUは省略可能
任意
コンテナレベルのメモリ コンテナ用に予約するメモリ量
コンテナレベルのメモリ合計量≦タスクレベルのメモリ
必須
タスクレベルでメモリを指定している場合、コンテナレベルのメモリは省略可能
任意

タスクレベルのCPUとコンテナレベルのCPU

CPU割り当てについては、タスクレベルのCPU定義が設定されている場合、コンテナはタスクレベルのCPU値を上限にリソースを使用できます。タスクレベルのCPU定義が設定されていない場合は、コンテナインスタンス上で使用可能なCPU上限までバーストすることができます。

CPUにはnullや0を指定することも可能ですが、その場合でも最低2CPU Unitsが割り当てられます。(1vCPU=1024CPU Units)

CPU のパラメータは必須ではなく、コンテナ定義で 2 以下の CPU 値を指定することも可能です。CPU 値に 2 未満 (null を含む) を設定した場合の動作は、Amazon ECS コンテナエージェントのバージョンによって異なります。
タスク定義パラメータ - Amazon Elastic Container Service より引用

メモリのソフト制限とハード制限

コンテナ定義にはmemoryReservationというメモリのソフト制限もあります。 コンテナは必要に応じてハード制限か、コンテナインスタンス上で使用可能なメモリ上限までバーストすることができます。

  • ソフト制限のみ
    • ソフト制限値は予約を表し、上限はコンテナインスタンスの合計メモリ量となる
  • ハード制限のみ
    • ハード制限値が予約かつ上限になる
  • ソフト制限とハード制限を両方
    • ソフト制限値は予約、ハード制限値は上限となる

具体例で見てみる

少しややこしいのでEC2起動タイプでc6i.largeインスタンス(2vCPU、メモリ4GB)を利用し、以下のようなリソース割り当てを例に考えてみます。

タスクレベル コンテナレベル
CPU(cpu) - 1024
メモリハード制限(memory) - 3072
メモリソフト制限(memoryReservation) - 2048

この場合コンテナのリソース利用は以下になります。

  • コンテナレベルのCPUに1024CPUユニットを予約しているので、このリソース分は最低限確保しておりいつでも使用できる
  • タスクレベルのCPUは指定していないかつ、インスタンスには1024CPUユニット分余りがあるため、コンテナは割り当てたCPUをバーストしてその空き容量を使用することができる
    • そのためタスクのCPU使用率は100%を超えることがある
  • コンテナレベルのメモリのソフト制限を指定しているため、コンテナは2048MBは最低限確保しておりこのリソース分はいつでも使用できる
  • メモリのソフト制限、ハード制限の両方を指定しているため、ソフト制限をバーストしてハード制限のメモリ量までリソースを使用することができる

さらにもうひとつタスクを起動したい場合を見てみます。

  • OKパターンでは各タスクで1024CPUユニット予約しているので、このリソース分は最低限確保しておりいつでも使用できる
  • NGパターンではインスタンスのメモリ空き容量よりも大きなメモリを予約しようとしているため2つ目のタスクは起動することができない

ENIトランキング

※ Fargate起動タイプでは専用のENIを受け取るためこの機能は必要ないです

ECSではネットワークモードにdefault, none, bridge, awsvpc, hostが選択できますが、このうちawsvpcネットワークモードを利用すると、ECSの各タスクにENIを割り当てることができます。

しかしEC2インスタンスにアタッチできるENI数には制限がある上、インスタンス自体のプライマリネットワークインターフェースとして1つは利用されています。

Amazon EC2 インスタンスにアタッチできるネットワークインターフェイスの数にはデフォルトの制限があり、プライマリネットワークインターフェイスも 1 つとしてカウントされます。たとえば、デフォルトでは c5.large インスタンスには最大 3 つの ENI がアタッチされています。このインスタンスのプライマリネットワークインターフェイスも 1 つとしてカウントされるため、このインスタンスに追加でアタッチできる ENI は 2 つです
Elastic Network Interface のトランキング - Amazon Elastic Container Service より引用

ドキュメントの通り、awsvpcネットワークモードのタスクは2つしか実行できないということになります。

ECSではENIトランキング機能を有効にすることで上限を超えてENIを追加することができます。

設定はとても簡単で、

  • コンソールから設定する場合

Amazon ECS→アカウント設定→AWSVPC Trunking で以下にチェックをいれるだけです。

  • terraformで設定する場合
resource "aws_ecs_account_setting_default" "default" {
  name  = "awsvpcTrunking"
  value = "enabled"
}

aws_ecs_account_setting_defaultリソースのawsvpcTrunkingをenabledすればOKです。

この設定によって、先の例で2つしかタスクを実行できなかったc5.largeも、上限緩和によって10個のタスクまでENIを割り当てて実行することが可能になります。

ひとつ注意点としてすべてのインスタンスタイプで利用できるわけではない、という点があります。
弊チームでは当初 r6i.large, r5.large, r5a.large, r5n.large のインスタンスタイプを使おうとしていましたが、このENI制限によって r6i と r5n は断念しました。
ENIトランキングサポート&東京リージョンで使えるインスタンスタイプを選定した結果、最終的には r5.large, r5a.large, m5.large, m5a.large, m6i.large のインスタンスを使用することになりました。

詳しくはサポートされているEC2インスタンスタイプを参照ください。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/container-instance-eni.html#eni-trunking-supported-instance-types

さいごに

ECSはフルマネージドなコンテナオーケストレーションサービスですが、実際に構築するとなるとタスクの起動タイプやリソース割り当ての設計、ネットワークモードの選択など設計ポイントがそれなりに多く、慣れないうちは頭を抱える人も多いんじゃないかと思います。 今回はわたしがECSの構築のときに毎回悩む起動タイプの判断、CPU、メモリのリソース割り当てについてと、はじめて知ったENIトランキング設定についてまとめてみました。このTipsがECS設計に悩める方の参考になれば幸いです。

© Sansan, Inc.