EventBridge Scheduler + Lambda で開発環境を平日朝に自動起動・夜間に自動停止してコスト削減する
このハンズオンでは、開発環境の 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 ルールはタイムゾーンを UTC で指定する必要がありましたが、2022 年にリリースされた EventBridge Scheduler はタイムゾーンを直接指定できます(例: Asia/Tokyo)。このハンズオンでは新しい Scheduler を使います。
| 操作 | 順序 | 理由 |
|---|---|---|
| 起動時 | EC2 → RDS(同時リクエスト) | 両方に起動リクエストを即座に送信。Lambda 関数内で順序制御不要 |
| 停止時 | RDS 先に停止 → EC2 停止 | RDS は停止処理に数分かかる。先にリクエストを出しておく |
「EC2 が running になってから RDS を起動」のような依存関係が必要な場合は、Step Functions 版ハンズオンを参照してください。
i-0abc1234567890def)と RDS DB 識別子(例: handson-db)を手元にメモしておくRDS には「7 日間停止後に自動起動する」制限があります。このハンズオンで設定する自動停止と競合する場合があります。長期間の自動停止を行う本番運用では、自動起動設定の無効化または Aurora Serverless への移行を検討してください。
Lambda が EC2 と RDS を操作するための IAM ロールを作成します。
{
"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 を検索して追加 → 「次へ」「ロールを作成」をクリックします。
「関数の作成」をクリックします。
lambda_function.py を開く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」ボタンをクリックしてコードを保存します。
「保存」をクリックします。
起動関数と同じ手順で停止関数を作成します。
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'
}
起動関数と同じ値を設定します。
タイムアウトも同様に 30 秒 に変更します。
| フィールド | 値 | 意味 |
|---|---|---|
| 分 | 0 | 0 分 |
| 時 | 8 | 8 時 |
| 日(月) | ? | 指定なし(曜日で指定するため) |
| 月 | * | 毎月 |
| 曜日 | MON-FRI | 月〜金 |
| 年 | * | 毎年 |
起動スケジューラーと同じ手順で停止スケジューラーを作成します。
スケジュール一覧に handson-start-schedule と handson-stop-schedule の 2 つが表示されて「有効」になっていれば設定完了です。
スケジュール実行を待たずに Lambda を手動テストで動作確認します。
test-stop → イベント JSON は {} のまま"statusCode": 200 が表示されれば成功{} → 「テスト」ボタンをクリックLambda の手動テストで EC2・RDS の停止・起動が正常に動作すれば、スケジューラーからも同様に動作します。以降は毎週月〜金の 8 時に自動起動、22 時に自動停止が実行されます。
EC2 i-xxxx: stopping や RDS handson-db: 停止リクエスト送信 のログが確認できるハンズオン完了後、不要なリソースを削除します。自動停止・起動を本番運用したい場合は削除不要です。
このハンズオンで作成した仕組みはそのまま本番運用に使えます。複数の EC2/RDS を管理したい場合は、環境変数をカンマ区切りのリストにして Lambda コードで split(',') して処理するか、Systems Manager Parameter Store に対象リストを保存する方法に拡張できます。