1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EventBridge Scheduler(L2コンストラクト)を用いたEC2の起動停止をCDKで実装する

Posted at

🕰️ 背景:EC2自動起動停止の歴史

従来

EC2インスタンスのコスト最適化として「営業時間外は停止する」というものはよくある構成かなと思います。
従来は、これを実現するために以下のような複雑な構成が必要でした。

  • Lambda関数でEC2の起動・停止処理を実装
  • EventBridge Rulesでスケジュール実行
  • IAMロールの適切な権限設定
  • エラーハンドリングログ出力の実装

EventBridge Schedulerの登場

2022年11月にリリースされたEventBridge Schedulerにより、この状況が大きく改善され、非常にシンプルな形でこの構成を組むことが可能になりました。
この時点ではCDKはL1コンストラクトのみの対応であり、なかなか使用しにくい物でした。

  • Lambdaを書かずに直接AWSサービスを呼び出し可能
  • より柔軟なスケジュール設定(ワンタイム実行、複雑なcron式など)
  • 組み込みのエラーハンドリングとリトライ機能

CDK L2コンストラクト対応の実現

そして2025年4月、ついにAWS CDKのL2コンストラクトとしてEventBridge Schedulerが利用可能になりました!

参考:AWS CDK Construct Library now supports Amazon EventBridge Scheduler

これにより、Infrastructure as Codeでの管理がより簡単になり、今回のようなEC2自動起動停止もCDKをデプロイするのみで実装できるようになりました!

今回はCDKでこの構成を構築します。

🔧 作成すべきリソース

今回のEC2自動起動停止を実現するために、以下のリソースを作成する必要があります。

  • Scheduler用のIAMロール - EC2の起動停止権限を持つ
  • ターゲット - 実際に実行するアクションを定義
  • Scheduler Group(任意) - スケジューラーの管理単位
  • Scheduler本体 - 実際のスケジュール設定

📖前提

EC2は既にCDKで作成済みである想定です。

const instance = new ec2.Instance(this, 'Instance', {
  ...
})

💻 実装

1. Scheduler用のIAMロール

まず、EventBridge SchedulerがEC2を起動停止するためのIAMロールを作成します:

import * as cdk from 'aws-cdk-lib';
import { aws_iam as iam } from 'aws-cdk-lib';

// ----- Scheduler Role -----
const schedulerRole = new iam.Role(this, 'SchedulerRole', {
  assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'),
  description: 'IAM role for EventBridge Scheduler to start/stop EC2',
});

schedulerRole.addToPolicy(
  new iam.PolicyStatement({
    actions: ['ec2:StartInstances', 'ec2:StopInstances'],
    resources: [
      cdk.Stack.of(this).formatArn({
        service: 'ec2',
        resource: 'instance',
        resourceName: props.targetEc2.instanceId,
      }),
    ],
  }),
);

scheduler.amazonaws.comサービスプリンシパルを使用し、対象のEC2インスタンスに対してのみ起動停止権限を付与しています。
本来であれば、起動用と停止用で分けるべきかと思いますが、今回は一緒にしちゃいます。

2. ターゲットの定義

次に、実際に実行するアクションを定義します:

import { aws_scheduler_targets as targets } from 'aws-cdk-lib';

const startTarget = new targets.Universal({
  service: 'ec2',
  action: 'startInstances',
  input: scheduler.ScheduleTargetInput.fromObject({
    InstanceIds: [props.targetEc2.instanceId],
  }),
  role: schedulerRole,
});

const stopTarget = new targets.Universal({
  service: 'ec2',
  action: 'stopInstances',
  input: scheduler.ScheduleTargetInput.fromObject({
    InstanceIds: [props.targetEc2.instanceId],
  }),
  role: schedulerRole,
});

aws_scheduler_targetsには、いくつかのテンプレートが用意されています。
マネコン経由で確認した場合、以下の種類があるようです。

image.png

ここに記載のないサービスに関しては、Universalを使って定義する必要があります。
今回はEC2が対象なので、上記のように記載します。

inputに関しては、マネジメントコンソールから実際のフォーマットを確認するのが早いです。
EC2の場合は以下のようになりますので、同じようにCDK上で指定しています。

image-1.png

3. Scheduler Group(任意)

import { aws_scheduler as scheduler } from 'aws-cdk-lib';

const scheduleGroup = new scheduler.ScheduleGroup(this, 'Group');

Scheduler Groupは、必須でというわけではありませんが、以下の観点から作成をしています。

  • メトリクスの管理: グループ単位でスケジューラーの実行状況を確認可能
  • 権限管理: グループレベルでのアクセス制御

指定しなければ「Default」のScheduler Groupが使用されます。

4. Scheduler本体

最後に、実際のスケジュール設定を行います。

import { aws_scheduler as scheduler } from 'aws-cdk-lib';

new scheduler.Schedule(this, 'StartSchedule', {
  schedule: scheduler.ScheduleExpression.cron({
    // 月曜日から金曜日の8:45に起動する
    minute: '45',
    hour: '8',
    month: '*',
    weekDay: 'MON-FRI',
    year: '*',
    timeZone: cdk.TimeZone.ASIA_TOKYO,
  }),
  target: startTarget,
  scheduleGroup: scheduleGroup,
});

視認性向上のため各項目を明示的に指定しています。省略した項目は自動的に「*」が設定されるので、ご注意ください。
また、weekDayday同時に定義不可です。

同様に停止用のスケジューラーも作成します。

new scheduler.Schedule(this, 'StopSchedule', {
  schedule: scheduler.ScheduleExpression.cron({
    // 毎日の20:00に停止する
    minute: '00',
    hour: '20',
    day: '*',
    month: '*',
    year: '*',
    timeZone: cdk.TimeZone.ASIA_TOKYO,
  }),
  target: stopTarget,
  scheduleGroup: scheduleGroup,
});

📊 作成されたリソースの確認

デプロイ後、AWSマネジメントコンソールで以下のように確認できます。

Scheduler Group

image-2.png

Scheduler

image-3.png

メトリクスを見る限り、無事に動作していることが確認できます!

🎯 まとめ

EventBridge SchedulerとCDKでEC2の停止機構を実装してみました。

DBとの連携が合って、起動順を考慮する必要がある場合はもう少し検討の余地ありですが、単にEC2を起動、停止するのみであれば、とても簡単に実装することができます。

これが少しでもお役に立てば幸いです!

📚 参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?