ECSサービスに複数のターゲットグループを登録できるようになりました!

「なんか同じタスク定義から別々のECSサービス作成されてるけど、これなんなん?」

「しゃーないやん、ターゲットグループ1つしか登録できへんねんから」

待望のアップデートです! Amazon ECS(EC2とFargate両方)において、ECSサービスに複数のターゲットグループをアタッチできるようになりました!

Amazon ECS サービスで複数のロードバランサーターゲットグループのサポートを開始

従来、ECSサービスに対してターゲットグループが1つしか登録できないために複数のロードバランサーを紐付けできなかったのが、複数登録できるようになりました。

ECSサービスを1つにまとめることで運用面でもランニング費用面でもメリットがありますが、逆に利用上注意が必要な点も多いので、そのあたりも合わせてお伝えいたします。

ターゲットグループつけ放題きたか…!!

  ( ゚д゚) ガタッ
  /   ヾ
__L| / ̄ ̄ ̄/_
  \/   /

ECSサービスに対してターゲットグループが1つ制限だったときの辛い点

例えば、ECSサービスをインターネット向けとオンプレミスからの両方に公開する場合を考えてみます。この場合、インターネット向けにはパブリックなALBを、オンプレミス向けにはインターナルなALBを用意するのが典型的な構成です。

この場合ALBが別となるので、以下のようにECSサービスを2つ用意する必要がありました。

ECSサービスに対して複数ターゲットグループが登録できる場合

一つのECSサービスに対して複数のターゲットグループが登録できるので、インターネット経由のトラフィックとオンプレミス経由のトラフィックを異なるALBから一つのECSサービスで受けることができます。

実際に設定してみる

ほな、実際に複数ターゲットグループを設定して行きましょう。公式ドキュメントはこちら。

サービスに複数のターゲットグループを登録する - Amazon Elastic Container Service

2019年8月19日現在、Webコンソールからの複数ターゲットグループ登録はできません。

現在、複数のターゲットグループを指定してサービスを作成する場合は、Amazon ECS API、SDK、AWS CLI、AWS CloudFormation テンプレートを使用してサービスを作成する必要があります。
引用:サービスに複数のターゲットグループを登録する

ので、ここでは、CloudFormationを利用して登録していきます。

ECSサービスに紐付けるロードバランサーとターゲットグループの作成

インターネット公開するpublic-albと、内部公開用のprivate-alb、およびそれぞれに紐づくターゲットグループを事前に作成します。

Webコンソールだと、ECSサービス作る時にターゲットグループの作成をあわせて実施できますが、今回はWebコンソールは使えないため、事前にターゲットグループも作成して、それぞれのARNを控えておきます。

CloudFormationによるECSサービスの作成

CloudFormationテンプレートへの複数ターゲットグループ指定方法ですが、上の公式ドキュメントにJSONの例が記載されているとおり、ECSサービスに紐づくLoadBalancerを配列で複数指定するだけです。下のCloudFormationテンプレートのハイライト部分を参考にしてみてください。

 AWSTemplateFormatVersion: '2010-09-09'
Description: ecs multiple tg service

Resources:
  service:
    Type: AWS::ECS::Service
    Properties:
      Cluster: container-insights-test
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 50
      DesiredCount: 1
      LaunchType: FARGATE
      LoadBalancers:
        - ContainerName: php-container
          ContainerPort: 80
          TargetGroupArn: arn:aws:elasticloadbalancing:ap-northeast-1:62989576XXXX:targetgroup/public-tg/a66f42619579a4b8
        - ContainerName: php-container
          ContainerPort: 80
          TargetGroupArn: arn:aws:elasticloadbalancing:ap-northeast-1:62989576XXXX:targetgroup/internal-tg/583e97e2acd5ef55
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - sg-4681a620
          Subnets:
            - subnet-f90cd2b0
            - subnet-e15343b9
      TaskDefinition: fargate-php-task:3

このテンプレートを元にECSサービスを作成します。指定内容にエラーが無ければ、無事サービス定義の中で、ターゲットグループが2つ登録されているのが表示されました!

ターゲットグループ内でコンテナに対してヘルスチェックがきちんと通っている状態であれば、無事双方のロードバランサーから中味のリクエストが帰ってきました。動作的にはOKです。

気になる挙動を試してみる

最低限の動作は確認できましたが、気になる点があったので、もう少し深堀りしてみます。

ターゲットグループは3つ以上登録できるのか?

特にドキュメントなどには記載が見当たらなかったのですが、ターゲットグループは2つ以上登録できます。とりあえず、3つは登録できました。

複数ターゲットグループのうち1つのヘルスチェックがUnhealthyの場合、タスクはどうなるか?

3つターゲットグループが登録され全てHealthyの状態から、1つのターゲットグループがUnhealthyになったとき、タスクはどうなるか検証してみました。

結論としては、ECSサービスに紐づく複数ターゲットグループのうち、どれか1つがUnhealthyになると、タスクは停止されます。

1つのターゲットグループのヘルスチェックパスを存在しないパスに変更し、404が返却されるように変更しました。タスクのログには以下で表示されています。

この状態でしばらく待つと、ヘルスチェックに失敗したターゲットグループを明示しタスクが停止します。

task failed ELB health checks in (target-group arn:aws:elasticloadbalancing:ap-northeast-1:62989576XXXX:targetgroup/public-tg2/1c38bf81f6e9e283)

このように、複数ターゲットグループが登録されているときECSサービスに対するヘルスチェックがどれか1つでもUnhealthyになった時点で、タスクが停止されることは注意しておきましょう。ターゲットグループには、タスク内の異なるコンテナへヘルスチェック設定できますが、ヘルスチェックがUnhealthyになった場合、タスクごと終了するということです。

その他注意事項

サービス定義で複数ターゲットグループを登録したときの注意点が公式マニュアルに記載されています。

・複数のターゲットグループは、Application Load Balancer または Network Load Balancer ロードバランサータイプを使用する場合にのみサポートされます。

・複数のターゲットグループは、サービスがローリング更新 (ECS) のデプロイコントローラータイプを使用する場合にのみサポートされます。CodeDeploy または外部デプロイコントローラーを使用している場合、複数のターゲットグループはサポートされていません。

・Fargate および EC2 の両方の起動タイプを使用するタスクを含むサービスでは、複数のターゲットグループがサポートされています。

引用:サービスに複数のターゲットグループを登録する - Amazon Elastic Container Service

ALBとNLBの併用ができるのは嬉しいですね。例えばインターネットアクセスはパブリックALBで受けて、プライベートリンク経由のアクセスをNLBで受けることも可能です。デプロイは、ローリングデプロイでしか使えません。まぁここらへんは当然といえば当然でしょう。またFargateとEC2の両方で使えるのも便利です。

ECSサービス複数ターゲットグループ登録のメリット

今回のアップデートで嬉しい点を挙げます。

メリット①「TCOの削減に寄与する」

ECSサービスを1つにまとめることで、運用の簡素化とランニングコストの低減が可能です。

同じ機能を提供したいのにトラフィックの種別が異なるため仕方なく別サービスにしていた場合、一つのECSサービスに集約することでコンテナ更新時の手間が省略でき、またコンテナリソースの有効活用が期待できます。

扱うリソースをへらすことはTCO削減の第一歩なので、集約できるところはどんどん集約してしまって良いでしょう。

メリット②「複数サービスを提供するECSタスクが作りやすくなる」

例えば、Jenkinsコンテナの場合、1つのコンテナでウェブインターフェース用にポート8080を、API用にポート50000を公開するといったことが簡単になります。

また、1タスク内にWebserverコンテナとDatabaseコンテナを同梱させ、それぞれをポートを分けて外部に公開するといったことも可能です。

1コンテナに複数のアプリやプロセスを同居させるのはアンチパターンになりますが、ECSのタスクには複数コンテナを登録できるので、うまくタスクやコンテナの粒度を設計することで従来できなかったサービスの提供が可能となります。

ECSサービス複数ターゲットグループ登録のデメリット

ただ、この機能を安易に導入することのデメリットもあります。いきなり構成変更する前に、以下の点が本当に許容できるか必ず確認しておきましょう。

デメリット①「ECSサービスの更新と運用が同じになる」

インターネットからのアクセスと社内からのアクセスは、サービス提供レベルが異なることが多いでしょう。もし双方のアクセスがECSサービス1つに集約されている場合、社内アクセスのみ緊急停止したりテスト的にタスク数を変更したりといった対応が難しくなります。

また、コンテナの更新も1つのECSサービスに対して行うことになるので、ECSサービスが1つだけだと先に社内向けにテスト用に最新バージョンのコンテナをデプロイして動作確認するといったこともできなくなります。

デメリット②「別トラフィックのログが混ざる」

利用用途によりますが、1つのECSサービスに集約することで、それぞれのトラフィックのコンテナログが混ざることも注意が必要です。基本的にコンテナログは、CloudWatch Logsを使う場合タスクIDでユニークに出力されますが、別トラフィックを1つのECSサービスの1つのコンテナで受ける場合、両方のログが1つのロググループに出力されることを覚悟しましょう。

デメリット③「セキュリティグループやサブネットなどのネットワーク設定も同じになる」

Fargateなど、ECSタスク定義でネットワークモードがawsvpcの場合、ECSサービスでセキュリティグループやサブネットなどの情報を登録します。本来的には各サービスの利用用途に応じてセキュリティグループは適切に制限すべきなので、ECSサービスを統一したからと言って不要な経路を公開しないように気をつけましょう。

まとめ「ECSによるコンテナワークロードが自由度が飛躍的に増加するアップデート」

現状、Webコンソールでの登録ができないのは難点ですが、設定自体は非常にシンプルと言える今回のアップデート。

上のデメリットに記載したとおり、アプリケーションの全ての機能を1つのECSサービスに集約する必要はありません。無理にやると余計めんどくさくなりますが、うまく使えばあなたのECSコンテナワークロードの運用を飛躍的に簡単にする可能性があります。

一度、現在のシステムに適用箇所があるかどうか、コレをきっかけに検討いただければと思います。

それでは、今日はこのへんで。濱田(@hamako9999)でした。