woshidan's blog

そんなことよりコードにダイブ。

ecs_deployによるECSのオートスケーリングとAWSのECSによるオートスケーリングの違いについて

今日は会社で管理しているOSSの一つ、ecs_deployに関連する話をECSの復習がてらします。

TL;DR

  • ecs_deploy gemでは、ECSへのデプロイに関するCapistranoタスクの定義とECSのオートスケーリングを行うスクリプトが入っている
  • ECSのオートスケーリングはAutoScaling Groupのdesiredの設定でクラスタ内のコンテナインスタンスの数を、ECSのサービスのdesired countの設定でタスクの数を調整する
    • AWSによるECSのオートスケーリングでは2つのレイヤーの調整は独立して動いているので、AutoScalingグループがまだタスクが動いているインスタンスを停止してエラーになることがある
    • ecs_auto_scaler のオートスケーリングの場合は、スケールイン時はECSインスタンス上のタスクの状態をしらべ、必要なタスクがうごていないことを確認してからAutoScaling Groupの設定の調整を行うようになっている

reproio/ecs_deploy のgemについて

ecs_deploy の gem は、各言語で作成されているECSへのデプロイを助けるスクリプト*1の一つで、特徴としてはECSのデプロイをCapistranoのタスクとして記述させるアプローチを取っていることだと思います。

ecs_deploy のgemの中身はおおまかにいって

があって、今回自分が仕事で触ったのは ecs_auto_scalerr の方なので、 ecs_auto_scaler についてもう少し説明していきます。

また、ややこしいので、この記事ではAWSが提供しているECSのService AutoScalingを「AWSによるECSのオートスケーリング」、ecs_deployに含まれるecs_auto_saclerによるオートスケーリングは 「ecs_auto_scaler のオートスケーリング」と記載することにします。

ECSのオートスケーリングのために、ECS ServiceとAutoScaling Groupの設定をいじる必要がある

ecs_auto_scaler はひらたくいうと、ECSのAutoScalingを行うスクリプトです。

このスクリプトが書かれたのは2016年1月には、まだAWSによるECSのオートスケーリングがありませんでした*2が、この二種類のオートスケーリングが行なっていることをおおまかにまとめると

  • CloudWatchのアラートを受け取って*3
    • ECSのサービスのdesired countを増減させる
    • AutoScaling Groupのdisiredを増減させる*4

ということをやっています。

Amazon Web Services ブログ > Amazon ECSでAuto Scalingによると、AWSによるECSのオートスケーリングの場合、

  • ECSのサービスのタスク数の調整には、ECS ServiceのScaling Policy
  • ECSのクラスターのコンテナ数の調整には、コンテナインスタンスが属するAutoScaling GroupのScaling Policy

を用いています。一方、ecs_auto_scaler のオートスケーリングは

  • タスク数、コンテナ数の増減のために直接ECSのタスクやAutoScaling Groupのコンテナインスタンスを止めたり、desired, desired countを変更するAPIを直接叩いたり

しています。

何が言いたいかというと、2つのオートスケーリングで利用している設定やAPIに多少違いはありますが、ECSのオートスケーリングは、ECSのサービスとクラスターのAutoScaling Groupの2つのレイヤーの設定を管理して行う必要があるわけです。

AWSによるECSのオートスケーリングとecs_auto_scaler のオートスケーリングの違い

それでは、この2つのオートスケーリングの方法の違いで一体どういう事態が生じるのでしょうか。

じつは、AWSによるECSのオートスケーリングでは、ECS ServiceのScaling PolicyとAutoScaling GroupのScaling Policyがそれぞれ独立して動いていて、AutoScaling GroupのScaling Policyによりまだタスクが動作しているコンテナインスタンスが停止となりエラーが発生することがあります。

この問題に対応するため、 ecs_auto_scaler ではスケールイン時はECSインスタンス上のタスクの状態をしらべ必要なタスクが動いていないことを確認してから、AutoScaling Groupの設定の調整を行うようになっています*5

AWSによるECSのオートスケーリングを使っている場合でもこの問題の対応は可能ですが*6、ecs_auto_scalerを利用するメリットとしては、ecs_deployの EcsDeploy::EcsAutoScaler を利用する場合、ECSインスタンス上のプロセスのチェックを含めたオートスケーリングの処理を 管理対象クラスタの外部のホストで行う*7ため、監視される側のインスタンスには特別な設定をしなくていい点でしょうか。

そのかわり、オートスケーリングのためにネットワークを経由してAWSAPIを叩くので、AWSAPIの回数制限*8を超えるような規模のクラスタ、たとえば200台くらいのコンテナインスタンスが存在するような大規模なクラスタの管理は難しそうです*9

書ける、と思ってたら割とかけなくて焦りました。。現場からは以上です。

*1:たとえば、pythonだと https://github.com/fabfuel/ecs-deploy , シェルスクリプト: https://github.com/silinternational/ecs-deploy/blob/develop/ecs-deploy, JSだと https://www.npmjs.com/package/ecs-deploy など

*2:https://aws.amazon.com/jp/blogs/news/automatic-scaling-with-amazon-ecs/ AWSによるECSのオートスケーリングがアナウンスされたのは2016年5月

*3:正確には少し違っていて、後発のターゲット追跡スケーリングポリシーはCloudWatchのアラートではなく、CloudWatchの特定のメトリクスを見て、その値が一定値に近づくようにする https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-autoscaling-targettracking.html

*4:MinやMaxなども増減させていますが、詳しくは https://dev.classmethod.jp/cloud/aws/comprehend-auto-scaling-desired-capacity/

*5:詳しくは https://github.com/reproio/ecs_deploy/blob/master/lib/ecs_deploy/auto_scaler.rb#L350-L356 あたり

*6:https://developers.cyberagent.co.jp/blog/archives/14664/

*7:ことが前提になっている、おそらく。

*8:ECSのAPIは1時間に1000回くらい叩くとエラーを返してくるようになるとかなんとか...

*9:なんとなく、200台超えてきたらインスタンスタイプ変えることの方を先に検討しそうな気もするけどAWS詳しくない...