AWSコスト削減の第一歩|EventBridge+Lambdaで実現するEC2自動起動・自動停止の構築手順

AWSを利用した開発環境や検証環境において、「EC2インスタンスが24時間365日稼働したままになっている」というケースは少なくありません。
「明日も使うかもしれないから」「つい停止し忘れてしまった」「誰が起動したインスタンスかわからず停止しづらい」といった理由で放置されたEC2は、運用担当者が気付かないうちに月々のAWS利用料金を増加させる原因となります。
AWSのコスト最適化というと、複雑なアーキテクチャの見直しやインスタンスサイズのチューニングをイメージされるかもしれません。しかし、「利用しない時間帯のリソースを確実に停止する」ことは、手軽に取り組めるコスト削減施策です。
本記事では、Amazon EventBridge SchedulerとAWS Lambdaを組み合わせ、EC2インスタンスの起動・停止を完全自動化する仕組みの構築手順をご紹介します。
この記事の目次
なぜEC2の自動起動・自動停止が必要なのか?
例えば、次のようなスケジュールで稼働している社内の開発環境を想定してみましょう。
- 利用時間:平日 9:00〜18:00
- 夜間・休日:利用しない
この場合、実際の利用時間は1日あたり約9時間です。しかし、EC2インスタンスを24時間起動したままにすると、利用していない残り15時間分に対してもコンピュート料金が発生し続けてしまいます。
【実際の利用時間と稼働時間の差】
■ 実際の利用時間:約9時間/日
■ 実際の稼働時間:24時間/日 ※15時間分の不要なコストが発生
対象となる開発サーバーや検証サーバーが複数台ある場合、こうした不要なコストはさらに増加します。
コスト削減効果の試算(m5.largeの例)
EC2の自動起動・自動停止によって、実際にどの程度のコスト削減が期待できるのでしょうか。開発環境でよく選ばれるm5.largeインスタンス(Linux/オンデマンド)を例に試算します。
【試算条件】
- インスタンスタイプ:m5.large
- オンデマンド料金概算:約20円/時間(※為替やリージョンにより変動します)
- 稼働条件:平日 9:00〜18:00(月20営業日)
24時間稼働し続けた場合
- 24時間×30日=720時間/月
- 720時間×20円=約14,400円/月
平日9:00〜18:00のみ稼働させた場合
- 9時間×20日=180時間/月
- 180時間×20円=約3,600円/月
削減効果
- 14,400円−3,600円=約10,800円/月(約75%のコスト削減)
m5.largeを1台自動停止にするだけで、月額約1万円のコスト削減が見込めます。
「Webサーバー」「APサーバー」「DBサーバー」の3台構成の場合、月額約32,400円(年間で約38万8,800円)を削減できます。運用の仕組みを一度整えるだけでこれだけの成果を得られるため、費用対効果の高い取り組みといえるでしょう。
EventBridgeとLambdaの役割
今回の自動化構成では、AWSの2つのサービスが連携して動作します。
[ スケジュール (cron) ]
│
▼
[ EventBridge Scheduler ] (目覚まし時計の役割)
│
▼
[ AWS Lambda ] (実行作業員の役割)
│
▼
[ Amazon EC2 ] (起動 / 停止)
- Amazon EventBridge Scheduler(目覚まし時計):あらかじめ設定したスケジュール(平日9:00、平日18:00など)に従って、処理を起動するトリガーとして機能します。
- AWS Lambda(作業員):EventBridgeからの通知を受け取り、EC2の起動・停止などの実際の処理を実行します。
構築手順
それでは、実際の構築ステップを解説します。
①IAMロールの作成(信頼関係と許可ポリシーの設定)
AWSのセキュリティベストプラクティスに基づき、「Lambda用」と「EventBridge Scheduler用」の2つのIAMロールを作成します。
ここで最も重要なのが「信頼関係(Trust Policy)」の設定です。信頼関係とは、「誰(どのAWSサービス)がこのロールを利用して作業(sts:AssumeRole)することを許可するか」を定義するセキュリティ設定です。この設定が正しくされていない場合、「The role defined for the function cannot be assumed」といったエラーが発生して処理が実行されません。
コンソールでの信頼関係の設定・編集手順
- IAMコンソールの「ロール」から対象のロールを選択します。
- 「信頼関係(Trust relationships)」 タブを開き、「信頼ポリシーを編集(Edit trust policy)」 をクリックします。
- エディタに以下のJSONコードを貼り付けて保存します。
Lambda用IAMロール(ロール名例:Lambda-EC2-StartStop-Role)
Lambda関数がEC2を操作し、CloudWatch Logsへログを出力するために必要なロールです。
- 信頼関係(Trust Policy):Lambdaサービス(lambda.amazonaws.com)にこのロールの引き受けを許可します。
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- 許可ポリシー(Permissions): AWSマネージドポリシーのAWSLambdaBasicExecutionRoleをアタッチした上で、以下のインラインポリシーを追加します。
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances"
],
"Resource": "*"
}
]
}
EventBridge Scheduler用IAMロール(ロール名例:Scheduler-InvokeLambda-Role)
EventBridge Schedulerが指定した時刻にLambda関数を呼び出すための実行ロールです。
- 信頼関係(Trust Policy): Schedulerサービス(scheduler.amazonaws.com)にこのロールの引き受けを許可します。
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "scheduler.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- 許可ポリシー(Permissions):
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": "*"
}
]
}
信頼ポリシーの主要キーの解説
- Effect: “Allow”:処理の実行を許可します。
- Principal.Service:許可を与えるサービス(lambda.amazonaws.comやscheduler.amazonaws.com)を指定します。この設定に誤りがあると、サービスがロールを使えなくなります。
- Action: “sts:AssumeRole”:ロールの権限を引き受ける(一時認証情報を取得する)特別なAPIアクションです。
②EC2起動・停止用Lambda関数の作成
次に、処理を行うPythonコードを準備します。作成した「Lambda用IAMロール」を割り当てて関数を作成します。
EC2起動用Lambda(関数名:ec2-auto-start)
Python
import boto3
ec2 = boto3.client('ec2')
# 対象のインスタンスIDを指定
INSTANCE_IDS = [
'i-0123456789abcdef0',
'i-0123456789abcdef1'
]
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=INSTANCE_IDS)
msg = f'{len(INSTANCE_IDS)} EC2 instances started'
print(msg) # CloudWatch Logsにログを出力
return {
'statusCode': 200,
'message': msg
}
EC2停止用Lambda(関数名:ec2-auto-stop)
Python
import boto3
ec2 = boto3.client('ec2')
# 対象のインスタンスIDを指定
INSTANCE_IDS = [
'i-0123456789abcdef0',
'i-0123456789abcdef1'
]
def lambda_handler(event, context):
ec2.stop_instances(InstanceIds=INSTANCE_IDS)
msg = f'{len(INSTANCE_IDS)} EC2 instances stopped'
print(msg) # CloudWatch Logsにログを出力
return {
'statusCode': 200,
'message': msg
}
実行ログの確認方法
Lambdaの実行結果やprint()で出力したメッセージは、Amazon CloudWatch Logs(ロググループ:/aws/lambda/関数名)で確認できます。また、Lambdaコンソールの「テスト」実行時にもレスポンス(Response)として直接表示されます。
③EventBridge Schedulerのスケジュール設定
作成したLambda関数を定期実行するため、EventBridge Schedulerでスケジュールを設定します。実行ロールには「EventBridge Scheduler用IAMロール」を指定します。
設定時の注意点(タイムゾーン表記)
EventBridgeのcron設定はUTC(協定世界時)で指定する必要があります。日本時間(JST)で運用する場合は、指定したい時刻から9時間引いた時刻を入力してください。
- 日本時間9:00(起動)=UTC 0:00→cron(0 0 ? * MON-FRI *)
- 日本時間18:00(停止)=UTC 9:00→cron(0 9 ? * MON-FRI *)

cron式の基本書式
Plaintext
cron(分 時 日 月 曜日 年)
| 項目 | 指定値 | 補足 |
| 分 | 0〜59 | |
| 時 | 0〜23 | ※ UTC時間で指定 |
| 日 | 1〜31 | 曜日を指定する場合は ? |
| 月 | 1〜12 | |
| 曜日 | SUN-SAT | 日を指定する場合は ? |
| 年 | 1970〜2199 |
設定する2つのスケジュール
- 起動用スケジュール(平日9:00 JST)
- cron指定:cron(0 0 ? * MON-FRI *)
- ターゲット:Lambda関数ec2-auto-start
- 停止用スケジュール(平日 18:00 JST)
- cron指定:cron(0 9 ? * MON-FRI *)
- ターゲット:Lambda関数ec2-auto-stop
発展編:タグベース運用で管理負荷を軽減する
先ほどのコードではインスタンスIDを直接コード内に記載(ハードコード)していましたが、開発サーバーが増減するたびにLambdaのコードを修正するのは手間がかかります。
そこで有効なのが、特定のタグが付与されたEC2インスタンスを動的に検知して処理する「タグベース運用」です。
タグ設定例
- Tag Key:AutoSchedule
- Tag Value:Enable
タグ判定付きLambdaコード(起動用の例)
Python
import boto3
ec2 = boto3.client('ec2')
def lambda_handler(event, context):
# AutoSchedule=Enable かつ 停止中(stopped) のインスタンスを検索
response = ec2.describe_instances(
Filters=[
{'Name': 'tag:AutoSchedule', 'Values': ['Enable']},
{'Name': 'instance-state-name', 'Values': ['stopped']}
]
)
instance_ids = []
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instance_ids.append(instance['InstanceId'])
if instance_ids:
ec2.start_instances(InstanceIds=instance_ids)
msg = f"Successfully started instances: {instance_ids}"
else:
msg = "No stopped target instances found."
print(msg)
return {'statusCode': 200, 'message': msg}
この設定を行うことで、新しく検証用サーバーを構築した際も、AutoSchedule=Enableタグを付与するだけで自動起動・自動停止の対象に加えることができ、運用負荷を大幅に削減できます。
まとめ
AWSのコスト最適化においては、大掛かりな構成変更だけでなく、不要な時間にサーバーを停止するといった基本的な運用の見直しも有効です。
今回ご紹介したEventBridge SchedulerとLambdaの組み合わせは、比較的少ない手順で導入でき、EC2の利用状況に応じたコスト削減につなげられる施策です。特に注意が必要なIAMの信頼関係(Trust Policy)設定のポイントさえ押さえておけばスムーズに構築できます。開発環境の停止忘れにお悩みの方は、ぜひ導入を検討してみてください。
サーバー運用・構築支援ならベアサポート
ベアサポートでは、長年のサーバー運用実績に基づき、クラウド・オンプレミスを問わずインフラの設計・構築から運用自動化、障害一次対応代行まで、お客さまの環境に合わせた最適なインフラ運用ソリューションをご提供しています。
「自社内のリソースだけではクラウドのコスト最適化や自動化まで手が回らない」「24時間365日の監視・運用体制を効率的に構築したい」といったお悩みがございましたら、ぜひベアサポートにご相談ください。