[小ネタ] ECS on EC2 で複数 Capacity Provider を1クラスターで実行してみる

2021.09.09

おはようございます、もきゅりんです。

Capacity Providers 重宝してますか?

今回は、今更ながらの Capacity Providers がお題です (対象は ECS on EC2)。

Capacity Providers の概念の解説および Fargate における Capacity Provider strategy については下記ブログで紹介されていますし、

ECS on EC2 での Cluster Auto Scaling (以下 CAS) をやってみたブログはこちらがあります。

ただ、1を聞いて0.5ぐらいを理解できれば幸いとなる脳の持ち主である自分は、複数の CapacityProviders とサービスとの関係がどうなるのかが、下記のように記載されていても、何だかいまひとつイメージできなかったので、触ってみました。

デフォルトのキャパシティープロバイダー戦略は、Amazon ECS クラスターに関連付けられています。これにより、カスタムキャパシティープロバイダー戦略または起動タイプが指定されていない場合に、クラスター内でサービスの作成またはスタンドアロンタスクの実行に使用されるキャパシティープロバイダー戦略が決まります。
各クラスターのデフォルトのキャパシティープロバイダー戦略を定義することがベストプラクティスと考えられています。

キャパシティープロバイダー戦略は、クラスターのデフォルトのキャパシティープロバイダー戦略がニーズを満たさない場合に、サービスの作成時またはスタンドアロンタスクの実行時に指定します。

ちなみに、CAS は、キャパシティープロバイダーを作成するときに「マネージドスケーリングを有効にすること」を意味します。

やること

1クラスターで以下のようなキャパシティープロバイダー戦略を実施してみたいと思います。

ProviderName Config Template AMI Type Service Base Weight
hoge-cp1 onDemandInstance t2.micro hoge-sv 1 1
hoge-cp2-spot spotInstance t2.small hoge-sv 0 1
fuga-cp1 onDemandInstance t3.micro fuga-sv 1 0

上記の onDemandInstance や t 系のインスタンスタイプは、 RI Instance とか M や C などで起動されている、と適宜想像してもらえたら嬉しいです。

(単一の AutoScaling グループ内で、複数インスタンスタイプの組み合わせでの起動させることもできるのですが、構成単純化のため上記の構成をとっています。)

設定

手順は以下ブログの通りです。

補足事項を記載しておきます。

起動設定を起動テンプレートに

上記ブログでは起動設定ですが、起動テンプレートに設定します。

hoge-cp1, hoge-cp2, fuga-cp1 のためにそれぞれ各起動テンプレートと Auto Scaling グループ とを別々に作成します。

本稿では、 コンテナインスタンスを Linux にしたいので、最新 AMI は以下ページを参考に取得します。

aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended

上記ブログにも記載されていますが、詳細設定からインスタンスに ecsInstanceRole (AmazonEC2ContainerServiceforEC2Role ポリシー) の付与と ECS コンテナエージェントの設定は忘れずにしておきます。

#!/bin/bash
echo ECS_CLUSTER=YOUR_CLUSTER_NAME >> /etc/ecs/ecs.config

config_template

config_templates

留意点

  • キャパシティープロバイダーの作成時にマネージドスケーリングが有効にする場合、Auto Scaling グループ の希望するカウントを 0 に設定できます。
  • キャパシティープロバイダーの作成時にマネージド終了保護を有効にしたい場合、Auto Scaling グループと Auto Scaling グループの各 Amazon EC2 インスタンスで、スケールインからのインスタンス保護も有効になっている必要があります。
    • マネージド終了保護を使用する場合は、マネージドスケーリングを有効にする必要があります。

asg_params

(ここでホストとなるインスタンススペックをしっかり把握せず、いい加減な最大値を入力して、タスク数を無計画に入れたためタスクが起動しないはめになりました。)

asg_groups

キャパシティプロバイダーの作成

空で作成したクラスターに、上で作成した3つのASGに対応するキャパシティプロバイダーを作成します。

capacity_providers

タスク定義を作成/サービス, タスクをデプロイ

タスク定義の作成では起動タイプの互換性の選択はEC2にするのを忘れずに。

今回、タスク定義のタスク CPU を 1024 (1vCPU) にしたため、1タスクで1台ずつ起動することになります。

サービス作成時にキャパシティプロバイダーを選択します。

hoge-sv は5タスクとしました。

そうすると、 hoge-cp1 は 1 (base) + 2 (weight) タスク(-> EC2インスタンス * 3), hoge-spot-cp2 に 2 (weight) タスク(->EC2インスタンス * 2)が実行されることになります。

fuga-sv は1 (base) タスク(-> ECインスタンス * 1)です。

(この後、 hoge-sv のタスクがいつまでも1つ上がってこず、あれ?何でだっけ?となりました。)

確認

(確認、修正の上) 上記の設定通りになりました。

さいごに

シンプルな設定での検証でしたが、自分の中でサービスごとにきめ細かく設定を検討できるキャパシティプロバイダーのイメージが付いてきました。

ASG はとても奥が深いですね。

普段、 Fargate にお任せに慣れすぎていて、ホストインスタンスのパフォーマンスとコンテナタスクサイズを計画的に考慮せずコンテナが起動してこない、という基本的なミスをしました。

AWS がサービスを提供する上で、本質的ではない考慮事項を省いていってくれることに改めて気付き、ありがとう AWS、そして恐るべし AWS、と感じました。

以上です。

どなたかのお役に立てば幸いです。

参考