📌

CircleCIでデプロイ時にAWSのECSタスクの稼働数を変更した

2023/07/11に公開

弊社ではCircleCIを利用してAWS上に構築したECS(Fargate)にアプリケーションをデプロイしています。

また、アプリケーションのレスポンスはCloudFrontでキャッシュしている為、デプロイ時のジョブでCloudFrontのキャッシュを削除する様にしています。

invalidate-cloudfront-cache
- run:
          name: CloudFrontキャッシュを削除
          command: aws cloudfront create-invalidation --distribution-id << parameters.cloudfront-id >> --paths "/*"

その際に問題となったのがECSタスクの稼働数です。リクエストの大部分がCloudFrontでキャッシュされるようになっており、オリジン(ECS)までリクエストが転送されることがないので、普段ECSのタスク数は最低稼働台数としている2台の状態ですが、アプリケーションをデプロイした際に、キャッシュをクリアすることで、一時的にオリジンへの負荷が高まり、オートスケーリングで稼働台数が増加していました。

この状態ですと、デプロイする度に一時的に負荷が高まるので、スケーリングされるまではユーザーのレスポンスが遅くなってしまう事が課題となっていました。

この問題を解決する為に考えた方法が、CloudFrontのキャッシュを削除するジョブの前後で、ECSの最低稼働台数を調節する事です。

CircleCIのデプロイフロー

具体的な処理は以下になります。

api-ecs-task-scale-out-production
#!/bin/bash

set -xeuo pipefail
set -u

###########################################################
#  バックエンドのECSタスク数をスケールアウトします.
###########################################################
case $ENV in
    "stg")
        ecs_task_min_capacity_count=4
        ecs_task_max_capacity_count=10
        ecs_cluster_name="stg-hogehoge-ecs-cluster"
        ecs_service_name="stg-hogehoge-ecs-service"
    ;;
    "prd")
        ecs_task_min_capacity_count=4
        ecs_task_max_capacity_count=20
        ecs_cluster_name="prd-hogehoge-ecs-cluster"
        ecs_service_name="prd-hogehoge-ecs-service"
    ;;
esac

# タスクの最低稼働数を更新
echo "Start updating tasks."
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/$ecs_cluster_name/$ecs_service_name \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity $ecs_task_min_capacity_count \
--max-capacity $ecs_task_max_capacity_count

# 指定したタスク数の稼働が確認出来るまで待機する
while [ "$(aws ecs describe-services \
--cluster $ecs_cluster_name \
--services $ecs_service_name \
| jq '.services[].runningCount')" -lt $(($ecs_task_min_capacity_count)) ]
do
  echo "Updating. Please wait a moment."
  sleep 10s
done

echo "Complete task update."
api-ecs-task-scale-in-production
#!/bin/bash

set -xeuo pipefail
set -u

###########################################################
#  バックエンドのECSタスク数をスケールインします.
###########################################################
case $ENV in
    "stg")
        ecs_task_min_capacity_count=2
        ecs_task_max_capacity_count=10
        ecs_cluster_name="stg-hogehoge-ecs-cluster"
        ecs_service_name="stg-hogehoge-ecs-service"
    ;;
    "prd")
        ecs_task_min_capacity_count=2
        ecs_task_max_capacity_count=20
        ecs_cluster_name="prd-hogehoge-ecs-cluster"
        ecs_service_name="prd-hogehoge-ecs-service"
    ;;
esac

# タスクの最低稼働数を更新
echo "Start updating tasks."
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/$ecs_cluster_name/$ecs_service_name \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity $ecs_task_min_capacity_count \
--max-capacity $ecs_task_max_capacity_count

echo "Complete task update."

こうすることで、キャッシュが削除されたタイミングでは、キャッシュがなくても耐えられる台数が稼働しており、必要がなくなったら元の最低稼働台数まで勝手に戻るので、コスト面でも無駄なく対応が出来ました。

もっと良い方法がありましたらご指摘お願いいたします。

Discussion