EC2 + RDS 自動停止・起動ハンズオン

EventBridge Scheduler + Lambda で開発環境を平日朝に自動起動・夜間に自動停止してコスト削減する

Amazon EventBridge Scheduler AWS Lambda Amazon EC2 Amazon RDS マネコン操作 入門〜中級 所要時間 60〜75 分 v1.0

📋 概要

このハンズオンでは、開発環境の EC2 インスタンスと RDS DB インスタンスを 平日朝 8 時に自動起動・夜 22 時に自動停止する仕組みを構築します。Lambda で EC2/RDS を操作し、EventBridge Scheduler で定時実行することで、稼働時間を 14 時間/日(平日のみ)に削減しコストを大幅に節約できます。

項目内容
所要時間60〜75 分
難易度入門〜中級
主要サービスEventBridge Scheduler、Lambda(Python)、EC2、RDS
前提リソース停止・起動できる EC2 インスタンスと RDS DB インスタンス
コスト削減効果24h 稼働 → 平日 14h のみ ≒ 約 70% 削減(週末停止込み)
ℹ️ EventBridge Scheduler(新)と EventBridge ルール(旧)の違い

従来の EventBridge ルールはタイムゾーンを UTC で指定する必要がありましたが、2022 年にリリースされた EventBridge Scheduler はタイムゾーンを直接指定できます(例: Asia/Tokyo)。このハンズオンでは新しい Scheduler を使います。

🏗️ 構成図

EventBridge Scheduler
起動スケジュール: cron(0 8 ? * MON-FRI *) Asia/Tokyo
停止スケジュール: cron(0 22 ? * MON-FRI *) Asia/Tokyo
↓ 定時起動
Lambda(起動用 / 停止用 それぞれ 1 つ)
↓ Boto3 API 呼び出し
🖥️ EC2 インスタンス   🗄️ RDS DB インスタンス

起動順序・停止順序

操作順序理由
起動時EC2 → RDS(同時リクエスト)両方に起動リクエストを即座に送信。Lambda 関数内で順序制御不要
停止時RDS 先に停止 → EC2 停止RDS は停止処理に数分かかる。先にリクエストを出しておく
ℹ️ より厳密な順序制御が必要な場合

「EC2 が running になってから RDS を起動」のような依存関係が必要な場合は、Step Functions 版ハンズオンを参照してください。

✅ 前提条件

⚠️ RDS の自動停止期間に注意

RDS には「7 日間停止後に自動起動する」制限があります。このハンズオンで設定する自動停止と競合する場合があります。長期間の自動停止を行う本番運用では、自動起動設定の無効化または Aurora Serverless への移行を検討してください。

EC2 インスタンス ID と RDS 識別子の確認方法

確認手順
  • EC2 インスタンス ID: EC2 コンソール → インスタンス → 対象インスタンスをクリック → 「インスタンス ID」(例: i-0abc1234)
  • RDS DB 識別子: RDS コンソール → データベース → 対象 DB をクリック → 「DB 識別子」(例: handson-db)

🔧 ステップ 1: Lambda 実行ロールの作成

Lambda が EC2 と RDS を操作するための IAM ロールを作成します。

1-1. IAM ポリシーの作成

手順
  1. IAM コンソール → 左メニュー「ポリシー」→「ポリシーを作成」
  2. 「JSON」タブを選択し、以下の JSON を貼り付ける
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:StartInstances",
        "ec2:StopInstances",
        "ec2:DescribeInstances"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "rds:StartDBInstance",
        "rds:StopDBInstance",
        "rds:DescribeDBInstances"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}
ポリシー名
handson-ec2rds-control-policy

「次へ」→「ポリシーの作成」をクリックします。

1-2. IAM ロールの作成

手順
  1. IAM コンソール → 「ロール」→「ロールを作成」
  2. 信頼されたエンティティタイプ: 「AWS のサービス」
  3. ユースケース: 「Lambda」 を選択 → 「次へ」
  4. 先ほど作成した handson-ec2rds-control-policy を検索して追加 → 「次へ」
ロール名
handson-lambda-ec2rds-role

「ロールを作成」をクリックします。

🔧 ステップ 2: 起動 Lambda 関数の作成

2-1. 関数の作成

手順
  1. Lambda コンソール → 「関数の作成」
  2. 「一から作成」を選択
関数名
handson-start-ec2rds
ランタイム
Python 3.12
アーキテクチャ
x86_64
実行ロール
既存のロールを使用 → handson-lambda-ec2rds-role

「関数の作成」をクリックします。

2-2. コードの入力

手順
  1. 「コードソース」セクションの lambda_function.py を開く
  2. 以下のコードを貼り付ける(既存のコードを全削除してから貼り付け)
import boto3
import os

ec2 = boto3.client('ec2')
rds = boto3.client('rds')

def lambda_handler(event, context):
    instance_id   = os.environ['EC2_INSTANCE_ID']
    db_identifier = os.environ['RDS_IDENTIFIER']

    # EC2 起動リクエスト
    ec2_resp = ec2.start_instances(InstanceIds=[instance_id])
    ec2_state = ec2_resp['StartingInstances'][0]['CurrentState']['Name']
    print(f'EC2 {instance_id}: {ec2_state}')

    # RDS 起動リクエスト
    rds.start_db_instance(DBInstanceIdentifier=db_identifier)
    print(f'RDS {db_identifier}: 起動リクエスト送信')

    return {
        'statusCode': 200,
        'ec2_state': ec2_state,
        'rds': 'starting'
    }

「Deploy」ボタンをクリックしてコードを保存します。

2-3. 環境変数の設定

手順
  1. 「設定」タブ → 「環境変数」→「編集」
  2. 「環境変数を追加」で以下の 2 つを追加する
キー: EC2_INSTANCE_ID
i-xxxxxxxxxxxxxxxxx(実際のインスタンス ID)
キー: RDS_IDENTIFIER
handson-db(実際の DB 識別子)

「保存」をクリックします。

2-4. タイムアウトの変更

手順
  1. 「設定」タブ → 「一般設定」→「編集」
  2. タイムアウト: 30 秒(デフォルト 3 秒から変更)
  3. 「保存」をクリック

🔧 ステップ 3: 停止 Lambda 関数の作成

起動関数と同じ手順で停止関数を作成します。

3-1. 関数の作成

関数名
handson-stop-ec2rds
ランタイム
Python 3.12
実行ロール
既存のロールを使用 → handson-lambda-ec2rds-role

3-2. コードの入力

import boto3
import os

ec2 = boto3.client('ec2')
rds = boto3.client('rds')

def lambda_handler(event, context):
    instance_id   = os.environ['EC2_INSTANCE_ID']
    db_identifier = os.environ['RDS_IDENTIFIER']

    # RDS を先に停止リクエスト(停止処理に時間がかかるため先出し)
    rds.stop_db_instance(DBInstanceIdentifier=db_identifier)
    print(f'RDS {db_identifier}: 停止リクエスト送信')

    # EC2 停止リクエスト
    ec2_resp = ec2.stop_instances(InstanceIds=[instance_id])
    ec2_state = ec2_resp['StoppingInstances'][0]['CurrentState']['Name']
    print(f'EC2 {instance_id}: {ec2_state}')

    return {
        'statusCode': 200,
        'ec2_state': ec2_state,
        'rds': 'stopping'
    }

3-3. 環境変数の設定

起動関数と同じ値を設定します。

キー: EC2_INSTANCE_ID
i-xxxxxxxxxxxxxxxxx(実際のインスタンス ID)
キー: RDS_IDENTIFIER
handson-db(実際の DB 識別子)

タイムアウトも同様に 30 秒 に変更します。

🔧 ステップ 4: 起動スケジューラーの設定

4-1. EventBridge Scheduler コンソールを開く

手順
  1. AWS コンソールで「EventBridge」を検索して開く
  2. 左メニュー → 「Scheduler」→「スケジュール」
  3. 「スケジュールを作成」 をクリック

4-2. スケジュールの設定

設定値
スケジュール名
handson-start-schedule
スケジュールグループ
default
オカレンス
定期的なスケジュール
スケジュールタイプ
Cron ベース
Cron 式
0 8 ? * MON-FRI *
タイムゾーン
Asia/Tokyo
ℹ️ Cron 式の読み方
フィールド意味
00 分
88 時
日(月)?指定なし(曜日で指定するため)
*毎月
曜日MON-FRI月〜金
*毎年

4-3. フレキシブルタイムウィンドウ

フレキシブルタイムウィンドウ
オフ(指定時刻ちょうどに実行)

4-4. ターゲットの設定

手順
  1. 「次へ」でターゲット設定へ進む
  2. 「テンプレートされたターゲット」→ 「AWS Lambda Invoke」 を選択
  3. Lambda 関数: handson-start-ec2rds を選択
  4. ペイロード(オプション): 空のまま OK

4-5. スケジューラー実行ロールの設定

手順
  1. 「次へ」でアクセス許可設定へ進む
  2. 実行ロール: 「このスケジュールの新しいロールを作成」(自動作成)
  3. ロール名は自動生成される(例: Amazon_EventBridge_Scheduler_LAMBDA_xxxxxxx)
  4. 「次へ」→「スケジュールを作成」をクリック

🔧 ステップ 5: 停止スケジューラーの設定

起動スケジューラーと同じ手順で停止スケジューラーを作成します。

設定値(起動と異なる箇所のみ)
スケジュール名
handson-stop-schedule
Cron 式
0 22 ? * MON-FRI *
タイムゾーン
Asia/Tokyo
Lambda 関数
handson-stop-ec2rds
✅ 確認

スケジュール一覧に handson-start-schedulehandson-stop-schedule の 2 つが表示されて「有効」になっていれば設定完了です。

🔧 ステップ 6: 動作確認

スケジュール実行を待たずに Lambda を手動テストで動作確認します。

6-1. 現在の EC2・RDS 状態を確認

手順
  1. EC2 コンソール → インスタンス → 対象インスタンスの状態を確認(例: running)
  2. RDS コンソール → データベース → 対象 DB の状態を確認(例: available)

6-2. 停止 Lambda を手動テスト実行

手順
  1. Lambda コンソール → handson-stop-ec2rds を開く
  2. 「テスト」タブ → イベント名: test-stop → イベント JSON は {} のまま
  3. 「テスト」 ボタンをクリック
  4. 「実行結果」に "statusCode": 200 が表示されれば成功

6-3. EC2・RDS が停止したことを確認

手順
  1. EC2 コンソール → インスタンス → 状態が 「stopped」 になるまで待機(1〜2 分)
  2. RDS コンソール → データベース → 状態が 「停止中」→「停止済み」 になるまで待機(3〜5 分)

6-4. 起動 Lambda を手動テスト実行

手順
  1. Lambda コンソール → handson-start-ec2rds → 「テスト」
  2. イベント JSON: {} → 「テスト」ボタンをクリック
  3. EC2 が 「running」、RDS が 「利用可能」 に戻ることを確認
✅ 確認

Lambda の手動テストで EC2・RDS の停止・起動が正常に動作すれば、スケジューラーからも同様に動作します。以降は毎週月〜金の 8 時に自動起動、22 時に自動停止が実行されます。

6-5. CloudWatch Logs でログを確認

手順
  1. Lambda コンソール → 関数 → 「モニタリング」タブ → 「CloudWatch のログを表示」
  2. 最新のログストリームを開く
  3. EC2 i-xxxx: stoppingRDS handson-db: 停止リクエスト送信 のログが確認できる

🧹 クリーンアップ

ハンズオン完了後、不要なリソースを削除します。自動停止・起動を本番運用したい場合は削除不要です。

削除手順

  1. EventBridge Scheduler の削除
    EventBridge コンソール → Scheduler → スケジュール → handson-start-schedule と handson-stop-schedule を選択 → 「削除」
  2. Lambda 関数の削除
    Lambda コンソール → 関数 → handson-start-ec2rds と handson-stop-ec2rds を選択 → 「削除」
  3. IAM ロール・ポリシーの削除
    IAM コンソール → ロール → handson-lambda-ec2rds-role → 削除
    IAM コンソール → ポリシー → handson-ec2rds-control-policy → 削除
    ※ Scheduler が自動作成したロール(Amazon_EventBridge_Scheduler_LAMBDA_xxx)も削除
ℹ️ 本番運用で使い続ける場合

このハンズオンで作成した仕組みはそのまま本番運用に使えます。複数の EC2/RDS を管理したい場合は、環境変数をカンマ区切りのリストにして Lambda コードで split(',') して処理するか、Systems Manager Parameter Store に対象リストを保存する方法に拡張できます。