Fargate Spotにおける各Provider毎のタスク数起動推移を検証してみた #reinvent

「わかるような、わかんないような…わからん!」

re:Invent2019で突然発表されたFargate Spot、皆さん既にいろいろ試されているでしょうか?先日、Fargate Spotについて、その内容と代表的な疑問点を下記記事にてまとめてみました。

Fargateをスポットで7割引で使うFargate Spotとは? #reinvent | Developers.IO

この記事では、各Providerの設定値を数パターン試しながら、実際にタスクを1〜10個まで起動しつつ各Providerが起動するロジックを検証ました。グラフも載せたので設定値ごとの各Providerの起動推移や、Fargate SpotのCapacity Provider戦略が一覧できます。

Fargate Spot、使ってみようと思っているけどよくわからないなぁと思う方は、是非上で紹介した記事と合わせて、この記事御覧ください。

(祭) ∧ ∧
 Y  ( ゚Д゚)
 Φ[_ソ__y_l〉     Fargate Spot マツリダワッショイ
    |_|_|
    し'´J

検証前の事前準備

今回は、AWS CLIを利用してrun taskを使って検証していきます。事前に、AWS CLIを最新バージョンに更新しておきます。

$ aws --version
aws-cli/1.16.298 Python/3.7.4 Darwin/19.0.0 botocore/1.13.34

FARGATEFARGATE_SPOTを定義したクラスターを作成します。

$ aws ecs create-cluster --cluster-name FargateSpotTestCluster --capacity-providers FARGATE FARGATE_SPOT

事前に任意の名前でECSタスク定義を作成しておきます。安定して起動するものであれば何でも構いません。ここでは、simple-nginx-taskという名前で、nginxのイメージを指定しただけのシンプルなタスク定義を使います。

run taskによるCapacity Providerを指定した起動方法

AWS CLIには、run-task--capacity-provider-strategyオプションが追加されているので、これを使います。

参考:run-task — AWS CLI 1.16.298 Command Reference

下記が実際にrun taskするときのスニペットです。

aws ecs run-task \
  --capacity-provider-strategy capacityProvider=FARGATE,weight=4,base=2 capacityProvider=FARGATE_SPOT,weight=1,base=0 \
  --network-configuration awsvpcConfiguration="{subnets=[subnet-010cd248,subnet-5456460c],securityGroups=[sg-09b8040d264243711],assignPublicIp=ENABLED}" \
  --cluster FargateSpotTestCluster \
  --task-definition simple-nginx-task:2 \
  --count 1 | jq '.tasks[].capacityProviderName' | sort | uniq -c
  • capacity-provider-strategy
    • FARGATE、およびFARGATE_SPOTの各プロバイダーのbaseweight
  • network-configuration
    • FARGATEのawsvpcネットワークモードだと指定が必須な、タスクを格納するネットワーク情報を指定
  • count
    • タスク実行時のタスク数を指定

run-taskコマンドは、実行時に標準出力に起動したタスクの詳細情報を返すので、それを受けて最後のjq '.tasks[].capacityProviderName' | sort | uniq -c で、生成されたタスクのcapacityProviderName毎の数を表示します。

run-taskの実行例

例えば、以下の条件で実行したときのスクリプトと実行結果はこちら。

ProviderName Base Weight
FARGATE 2 1
FARGATE_SPOT 0 3

タスク数を8で指定。

$ aws ecs run-task \
  --capacity-provider-strategy capacityProvider=FARGATE,weight=1,base=2 capacityProvider=FARGATE_SPOT,weight=3,base=0 \
  --network-configuration awsvpcConfiguration="{subnets=[subnet-010cd248,subnet-5456460c],securityGroups=[sg-09b8040d264243711],assignPublicIp=ENABLED}" \
  --cluster FargateSpotTestCluster \
  --task-definition simple-nginx-task:2 \
  --count 8 | jq '.tasks[].capacityProviderName' | sort | uniq -c
   4 "FARGATE"
   4 "FARGATE_SPOT"

こんな感じで、プロビジョニングされたタスクのcapacityProviderNameが表示され、各Provider毎の起動数がわかるというわけです。

一点実施上の注意点ですが、ECSクラスター内でruntaskでタスク実行したのと都度全てのタスクを停止して検証しています。

ここまで準備ができたところで、実際に検証していきましょう。

FARGATEとFARGATE_SPOTのWeightが同じ場合

Baseが0の場合

最初に、Baseを設定せずに、Weightの比率を同じにします。

ProviderName Base Weight
FARGATE 0 1
FARGATE_SPOT 0 1

合計タスク数毎の各Providerタスク数遷移がこちら。

合計タスク数 1 2 3 4 5 6 7 8 9 10
FARGATE 1 1 2 2 3 3 4 4 5 5
FARGATE_SPOT 0 1 1 2 2 3 3 4 4 5

一点興味深いのは、タスク数が奇数でWeightで割り切れないときは常にFARGATEが優先して起動されているということです。ここらへんは、マニュアルにも特に記載が無いように見えるのですが、どちらかを利用する場合は、確実に起動できるオンデマンドのFARGATE側を優先するロジックのようです。

グラフにすると、常に、FARGATE側が多いのがわかります。

Baseが2の場合

Weightの比率を同じにしたまま、FARGATEにBase=2を指定します。

ProviderName Base Weight
FARGATE 2 1
FARGATE_SPOT 0 1

合計タスク数毎の各Providerタスク数遷移がこちら。

合計タスク数 1 2 3 4 5 6 7 8 9 10
FARGATE 1 2 3 3 4 4 5 5 6 6
FARGATE_SPOT 0 0 0 1 1 2 2 3 3 4

Baseで指定した2が先に起動されそれがベースのタスクとなり、その後起動されたタスクはWeightの比率で割り振られています。ここでも、奇数タスクの場合は、FARGATEが優先されています。

FARGATEとFARGATE_SPOTのWeightが異なる場合

Baseが0の場合

次に、各ProviderごとのWeightが異なる場合を検証します。

ProviderName Base Weight
FARGATE 0 4
FARGATE_SPOT 0 1

合計タスク数毎の各Providerタスク数遷移がこちら。

合計タスク数 1 2 3 4 5 6 7 8 9 10
FARGATE 1 2 2 3 4 5 6 6 7 8
FARGATE_SPOT 0 0 1 1 1 1 1 2 2 2

Weight比率は4:1ですが、タスク数3つ目でFARGATE_SPOTが起動しています。ロジックとしては、恐らくWeight比率に対して一番タスク数比率が近くなるような順番で起動していると考えられます。

Baseが4の場合

最後に、Baseを指定して、異なるWeight比率で検証してみます。

ProviderName Base Weight
FARGATE 4 1
FARGATE_SPOT 0 4

合計タスク数毎の各Providerタスク数遷移がこちら。

合計タスク数 1 2 3 4 5 6 7 8 9 10
FARGATE 1 2 3 4 4 4 5 5 5 5
FARGATE_SPOT 0 0 0 0 1 2 2 3 4 5

最初のうちは、Baseを最優先で確保。Base指定分のタスクが起動した後、Weight比率にのっとり、その後のProvider指定したタスクが起動しています。

タスク起動優先順位についての検証まとめ

とりあえず、一通り動かしてみたところ、以下のロジックで各Providerごとのタスクが起動しています。

  • Weight比率が指定の比率に一番近くなるProviderが追加される
  • 追加後のWeight比率が同じ場合、FARGATEがFARGATE_SPOTより優先される
  • Baseのタスク数は、Weight比率計算の対象外

1つめと2つめについては、公式ドキュメントにその旨記載が見当たらなかったので将来変更される可能性もありますが、2019年12月時点では、このロジックになっています。

実際にタスク数遷移を追いながら各設定値の意味を噛み締めてみました。ドキュメント読むだけでは理解が曖昧な点が多々あったので、ようやくイメージが掴めた感じです。疲れたけど、やってみてよかった。

皆さんも、これらのグラフやタスク数遷移を参考にしていただきつつ、現場で運用されているコンテナワークロードにマッチするCapacity Providerの設定値を模索していただければと思います。

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