Amazon EventBridge SchedulerでECS Fargateのタスクを定期起動・定期停止してみた

2022.11.17

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

「Event Bridge Schedulerを使えば、ECS FargateのサービスをLambda無しで定期起動・定期停止できる」

夜間など使わない時間は検証環境のECS Fargateを止めて料金節約したいことがあると思います。

ECS Fargate サービスの自動起動停止に関しては、Instance Schedulerも対応しておらず自前でLambdaを書くなどする必要がありました。

先日リリースされたEvent Bridge Schedulerを使えば、Lambdaを書かずに簡単に定期起動・定期停止を実現できます。

前提

定期停止と定期起動は以下を指しています。

  • 定期停止: ECS Fargateサービスのタスク数(desiredCount)を0にする
  • 定期起動: ECS Fargateサービスのタスク数(desiredCount)を元の数に戻す

そのため、1つのサービスあたり起動と停止で2つのスケジュールが必要になります。

今回は検証環境を定期起動・定期停止する場合を想定して、平日の20時に停止・平日の8時に起動するスケジュールを設定します。

やってみる

事前準備

検証用の環境はAWS CDKで用意します。

現時点(2022/11 )では、AWS CDKがEvent Bridge Schedulerに対応していないためEvent Bridge Schedulerの部分は手動で対応します。

AWS CDK v2.51.0でL1 Constructが対応しました。

aws-cdk-lib.aws_scheduler module · AWS CDK

lib/sample-ecs.ts

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2'
import * as ecs from 'aws-cdk-lib/aws-ecs'
import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns'
import * as iam from 'aws-cdk-lib/aws-iam'

export class EcsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // VPC
    const vpc = new ec2.Vpc(this, "Vpc", {
      vpcName: "sample-ecs",
      natGateways: 1
    })
    // ECSクラスター
    const cluster = new ecs.Cluster(this, "Cluster", {
      clusterName: "sample-cluster",
      vpc
    })
    // ECSサービス
    const ecsService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, "EcsService", {
      cluster,
      memoryLimitMiB: 1024,
      cpu: 512,
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
      },
      desiredCount: 2,
      serviceName: "sample-service",
    })
    // 検証用のためターゲットの解除時間を短くする
    ecsService.targetGroup.setAttribute(
      "deregistration_delay.timeout_seconds",
      "30"
    )
    // IAMロール
    const ecsStartStopRole = new iam.Role(this, "EcsStartStopRole", {
      assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'),
      roleName: 'ecs-start-stop-role'
    })
    const policy = new iam.PolicyStatement({
      actions: [
        'ecs:UpdateService'
      ],
      resources: ["*"]
    })
    ecsStartStopRole.addToPolicy(policy)
  }
}

Event Bridge Scheduelerの設定(定期停止)

スケジュールの詳細の指定

以下を設定します。cron式は平日20時に実行されるように設定します。

  • スケジュール名: ecs-sample-stop-weekday
  • cron式: 00 20 ? * MON-FRI *

Schedule types on EventBridge Scheduler - EventBridge Scheduler

タイムゾーンが意図したものになっているか確認して、次に進みます。

ターゲットの選択

サービスの検索>検索バーにECS>検索バーにUpdateServiceの順に進んで、Amazon ECS UpdateServiceを選択します。 JSONパラメータには以下を渡します。

{ 
    "Service": "<サービス名>", 
    "Cluster": "<クラスター名>",
    "DesiredCount": 0
}

設定

最後にCDKで作成した、IAMロール「ecs-start-stop-role」を指定して、次に進みます。

最後に確認画面が出るので、問題なければスケジュール作成を行います。

Event Bridge Scheduelerの設定(定期起動)

上記と手順は基本的に同じです。異なる部分だけ記載します。

スケジュールの詳細の指定

以下を設定します。cron式は平日8時に実行されるように設定します。

  • スケジュール名: ecs-sample-start-weekday
  • cron式: 00 8 ? * MON-FRI *

ターゲットの選択

ターゲットは同様にAmazon ECS UpdateServiceを指定します。 JSONパラメータのDesiredCountだけ変更します。

{ 
    "Service": "<サービス名>", 
    "Cluster": "<クラスター名>",
    "DesiredCount": <必要なタスク数>
}

動作確認

テスト用に時間を変えてスケジューラを実行してみました。(11:55実行)

設定した時間にタスクのdrainingが発生して、タスクの必要数が「0」になっていることを確認できました。

おわりに

「Amazon EventBridge SchedulerでECS Fargateのタスクを定期起動・定期停止してみた」でした。

EventBridge Schedulerのみ用意すれば定期起動・定期停止ができるので導入のハードルが下がったと思います。

TerraformやCDKでECSモジュールを作ってその中に、STG環境だったら定期起動・定期停止のEventBridge Schedulerを追加するといった処理を追加したら便利かもしれません。

以上、AWS事業本部の佐藤(@chari7311)でした。

参考

UpdateService - Amazon Elastic Container Service