Amazon CloudWatch Eventsを利用してECSサービスのスケールアップ・スケールダウンに対応してみた

Amazon ECS

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンニチハ、千葉です。

Amazon CloudWatch Events皆さんはもうお使いででしょうか!

今まではCloudWatch+SNS+LambdaやってきたことをCloudWatch Eventsを利用することで、イベントドリブンなアクション(Lambda実行タイミングの迅速化)したり、SNSを利用しないので構成をシンプルにできます。 (CloudWatch+SNS+Lambdaだと、ポーリングでの検知なので最大でも実行までに1分かかってしまいます)

今回は、CloudWatch Eventsを使ったECSのAutoScalingに対応してみたいと思います。

こちらを参考にやってみます。

動作イメージ図

AutoScalingをトリガーに、ECSサービスのDesiredをアップデートするLambdaファンクションが実行されるようにします。

ecs-cloudwach-events-0

Lambdaファンクションを作成

ECSのDesiredをアップデートするファンクションを作成します (ファンクションの作成手順は省略です)

import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    try:
        # get params
        AutoScalingGroupName = event['AutoScalingName']
        EcsClusterName = event['EcsClusterName']
        EcsServiceName = event['EcsServiceName']
        EcsRegion = event['EcsRegion']

        client_autoscaling = boto3.client('autoscaling')
        response = client_autoscaling.describe_auto_scaling_groups(
                AutoScalingGroupNames=[
                    AutoScalingGroupName
                ],
        )
        DesiredCapacity = response['AutoScalingGroups'][0]['DesiredCapacity']

        # update ecs service
        client_ecs = boto3.client('ecs')
        response = client_ecs.update_service(
            cluster = EcsClusterName,
            service = EcsServiceName,
            desiredCount = DesiredCapacity
        )

        logger.info( "EcsClusterName:" + EcsClusterName + ", EcsServiceName:" + EcsServiceName + ", DesiredCapacity:" + DesiredCapacity)
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

CloudWatchの設定

ルールを作成します

ecs-cloudwach-events-1

ecs-cloudwach-events-2

  • トリガー:AutoScalingによるEC2の作成成功、削除成功のタイミングを指定
  • トリガーの対象として、AutoScaling名を指定
  • ターゲットに、Lambdaファンクションを指定(事前に作成したLambdaファンクションを指定します)
  • Lambdaのインプットにjsonを指定できるので指定(ここに対象のECSのパラメータを指定します)

インプットの例

{"AutoScalingName": "ecs-cluster-2", "EcsClusterName": "docker-build", "EcsServiceName": "sample-webapp", "EcsRegion": "ap-northeast-1" }

ポイントは、Lambdaへインプットとしてjsonを渡せます。変数としてサービス固有値を外に出すことで汎用的にLambdaファンクションを使いまわせるので便利です。

やってみた

ECSサービスの現在のDesiredの数は、「1」です。

ecs-cloudwach-events-5

AutoScalingの「希望(Desired)」の値を1から2に変更します。これでAutoScalingが実行され、CloudWatch EventsよりECSサービスのDesiredをアップデートするLambdaファンクションが実行されます。

ecs-cloudwach-events-4

Lambdaファンクションが実行され、ECSサービスのDesiredも2になっていることを確認できました。

ecs-cloudwach-events-6

(スケールダウン時もAutoScalingの「希望(Desired)」の値に追従して、ECSサービスのDesiredも変更されるところまで確認できています)

最後に

CloudWatch Eventsを利用することで設定も簡略化され構成もシンプルになりました。

また、イベントドリブンでAWS上のAPI操作をできるということで、かなり汎用的な実装が可能になったのではないかと思います。