はじめに
検証用のEC2を作ったあと、つい停止し忘れることがあります。
1台なら金額は小さく見えても、検証環境が増えると地味に効きます。さらに、チームで使う環境では「誰が止めるのか」が曖昧になりがちです。
この記事では、 Amazon EventBridge Scheduler からEC2の StopInstances API を直接実行し、毎日18時にEC2を自動停止する手順を整理します。
Lambda関数は作りません。1台または数台の検証用EC2を止めたいだけなら、まずこの構成から検討すると分かりやすいです。
この記事でわかること
- EventBridge SchedulerでEC2を定時停止する考え方
- 毎日18時、平日18時のcron式
-
StopInstancesに渡す入力JSON - 実行ロールに必要なIAM権限
- 失敗時に見るCloudWatchメトリクスとDLQ
- Auto Scalingグループ配下のEC2で注意すること
先に結論
1台または数台のEC2なら、EventBridge SchedulerからEC2の StopInstances APIを直接呼ぶ構成が簡単です。
EventBridge Scheduler
-> EC2 StopInstances API
-> 対象EC2を停止
毎日18時に止める設定値は次の組み合わせです。
| 項目 | 設定値 |
|---|---|
| タイムゾーン | Asia/Tokyo |
| コンソールのcron式 | 0 18 * * ? * |
| CLI/APIのcron式 | cron(0 18 * * ? *) |
| ターゲット | EC2 StopInstances API |
| CLI/APIのターゲットARN | arn:aws:scheduler:::aws-sdk:ec2:stopInstances |
| 入力 | {"InstanceIds":["i-0123456789abcdef0"]} |
平日だけ18時に止めるなら、cron式は次のようにします。
0 18 ? * MON-FRI *
Auto Scalingグループ配下のEC2を直接停止すると、異常と判断されて別インスタンスに置き換えられることがあります。その場合はEC2単体の停止ではなく、Auto Scalingグループのスケジュールされたスケーリングを使う方が安全です。
前提
- 仕様確認日: 2026-08-05
- 対象読者: 検証用EC2の停止忘れを減らしたい人
- 対象環境: Amazon EBS-backed EC2
- リージョン例: 東京リージョン
ap-northeast-1 - 扱う範囲: EventBridge SchedulerでEC2を停止する最小構成
- 扱わない範囲: 起動スケジュール、複雑なタグ抽出、複数アカウント横断運用
この記事では、スケジュールを作るリージョンと対象EC2のリージョンをそろえる前提で説明します。
用語の短い説明
| 用語 | 短い説明 |
|---|---|
| EC2 | AWS上で仮想サーバーを起動できるサービス |
| EventBridge Scheduler | 指定した時刻や間隔でAWSサービスのAPIなどを呼び出せるスケジューリング機能 |
| ユニバーサルターゲット | EventBridge SchedulerからAWSサービスのAPIを直接呼び出す指定方法 |
StopInstances |
EC2インスタンスを停止するAPI |
| IAMロール | AWSサービスやユーザーに、一時的に権限を渡すための役割 |
| cron式 | 「毎日18時」「平日9時」などの繰り返し時刻を表す書き方 |
| DLQ | Dead-letter queue。ターゲット呼び出しに失敗したイベントをあとから確認するためのキュー |
| Auto Scalingグループ | EC2台数を自動調整し、指定した台数を保つ仕組み |
なぜLambdaを使わないのか
以前なら、定期実行でLambdaを起動し、LambdaからEC2を停止する構成を考えがちでした。
ただ、今回のように「決まった時刻に、決まったEC2へ StopInstances を投げる」だけなら、Lambdaを書く必要は薄いです。
| 方法 | 向いている場面 |
|---|---|
EventBridge Schedulerから直接 StopInstances
|
対象EC2が固定。1台または数台を単純に止めたい |
| Lambda経由 | タグで対象を検索する、条件分岐する、通知するなど処理が必要 |
| Auto Scalingのスケジュール | Auto Scalingグループ配下の台数を時間で変えたい |
EventBridge Schedulerのユニバーサルターゲットは、AWSサービスのAPI名と入力JSONを指定して実行できます。
実行時は、Schedulerが引き受けるIAMロールにターゲットAPIの権限が必要です。
今回のポイントは次です。
| 項目 | 値 |
|---|---|
| 呼び出すAPI | EC2 StopInstances
|
| CLI/APIで指定するターゲットARN | arn:aws:scheduler:::aws-sdk:ec2:stopInstances |
| 入力JSON | {"InstanceIds":["対象のEC2インスタンスID"]} |
| 実行ロールに必要な権限 | ec2:StopInstances |
Arn の stopInstances は、EC2 API名の StopInstances とは大文字小文字が違います。
EventBridge Schedulerのユニバーサルターゲットでは、AWS SDKのAPIアクション名に合わせて指定します。
設定手順
1. 対象EC2のインスタンスIDを確認する
EC2コンソールの「インスタンス」画面で、停止したいインスタンスIDを確認します。
i-0123456789abcdef0
東京リージョンのEC2なら、画面右上のリージョンが ap-northeast-1 になっていることも確認します。
インスタンスIDは環境ごとに違います。記事や手順書へ貼るときは、本番環境の実IDをそのまま公開しないようにします。
2. EventBridge Schedulerを開く
AWSマネジメントコンソールで次の順に進みます。
Amazon EventBridge
-> スケジュール
-> スケジュールを作成
ここで選ぶのは、EventBridgeの「ルール」ではなく スケジュール です。
3. 18時のスケジュールを設定する
入力例は次のとおりです。
スケジュール名:
stop-ec2-at-1800
頻度:
定期的なスケジュール
スケジュールの種類:
cronベースのスケジュール
タイムゾーン:
Asia/Tokyo
フレックスタイムウィンドウ:
オフ
毎日18時に停止するcron式は次です。
0 18 * * ? *
平日だけ18時に停止するなら次です。
0 18 ? * MON-FRI *
CLIやSDKでは、cron(...) の形で指定します。
cron(0 18 * * ? *)
EventBridge Schedulerは、指定したタイムゾーンでcron式を評価できます。ターゲット呼び出しは60秒精度なので、18:00ちょうどに設定した場合でも、実際の呼び出しは18:00:00から18:00:59の間に行われる前提で考えます。
EventBridge Schedulerのcron式は6フィールドです。
分、時、日、月、曜日、年の順で書きます。
日と曜日の両方を具体指定できないため、毎日なら 0 18 * * ? *、平日なら 0 18 ? * MON-FRI * のように片方へ ? を入れます。
4. EC2の停止APIを指定する
「ターゲットの選択」では、次のように選びます。
ターゲットAPI:
すべてのAPI
サービス:
Amazon EC2
API:
StopInstances
入力JSONには、停止したいEC2のインスタンスIDを入れます。
{
"InstanceIds": [
"i-0123456789abcdef0"
]
}
複数台をまとめて停止したい場合は、配列に追加します。
{
"InstanceIds": [
"i-0123456789abcdef0",
"i-0abcdef1234567890"
]
}
JSONにはコメントを書けません。その代わり、手順書側に「どのEC2を止めるか」「なぜ止めるか」を残しておくと、あとから見直しやすくなります。
5. IAMロールを作成する
コンソールに次の選択肢が表示されていれば、それを使うのが簡単です。
このスケジュール用に新しいロールを作成
ロール名の例です。
EventBridgeSchedulerStopEC2Role
既存ロールを使う場合は、EventBridge Schedulerがそのロールを引き受けられる信頼ポリシーと、EC2停止APIを呼べる権限が必要です。
信頼ポリシーの最小例です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "scheduler.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
本番環境や共有アカウントで実行ロールを手作りする場合は、さらに aws:SourceAccount と aws:SourceArn で、どのSchedulerから引き受けられるかを絞る方が安全です。
AWS公式ドキュメントでは、aws:SourceArn は個別スケジュールではなくスケジュールグループARNに絞る説明になっています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "scheduler.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012",
"aws:SourceArn": "arn:aws:scheduler:ap-northeast-1:123456789012:schedule-group/default"
}
}
}
]
}
個人学習では、まずコンソールの「このスケジュール用に新しいロールを作成」を使う方が楽です。
自分で信頼ポリシーを書く場合は、上のようにアカウントIDとスケジュールグループを自分の環境へ置き換えます。
EC2停止権限の例です。123456789012 はAWSアカウントID、i-0123456789abcdef0 は対象のインスタンスIDに置き換えます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:StopInstances",
"Resource": "arn:aws:ec2:ap-northeast-1:123456789012:instance/i-0123456789abcdef0"
}
]
}
StopInstances は、特定EC2インスタンスのARNに絞って許可できます。検証用でも、まずは対象リソースを絞る方針にしておくと安全です。
6. 作成して動作確認する
最後に内容を確認して、スケジュールを作成します。
作成後は、一覧で次の状態になっていることを確認します。
ステータス:
有効
最初の動作確認では、いきなり18時まで待たず、いったん現在時刻の5分後などに設定してEC2が停止するかを確認すると安心です。確認できたら、スケジュールを18時に戻します。
失敗を見逃さないための確認
個人学習なら、まずはCloudTrailとEC2の状態確認だけでも十分です。
ただ、共有環境や本番に近い検証環境では、失敗時に気づけるようにしておきます。
| 確認先 | 見るもの |
|---|---|
| EC2 | 対象インスタンスが stopping から stopped になったか |
| CloudTrail |
StopInstances が記録されているか |
| CloudWatch metrics |
InvocationAttemptCount、TargetErrorCount、InvocationDroppedCount
|
| DLQ | ターゲット呼び出し失敗時の詳細 |
EventBridge Schedulerでは、ターゲット呼び出しに失敗したイベントをSQS標準キューへ送るDLQを設定できます。
DLQは必須ではありませんが、IAM権限ミスや入力JSONミスをあとから追いやすくなります。
DLQを使う場合は、実行ロールにSQSへ送信する権限も追加します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:ap-northeast-1:123456789012:scheduler-dlq"
}
]
}
CLIでDLQを含める場合は、--target の中に DeadLetterConfig を追加します。
# DLQ付きでスケジュールを作る例。SQSキューARNは自分の環境へ置き換える
aws scheduler create-schedule \
--region ap-northeast-1 \
--name stop-ec2-at-1800 \
--schedule-expression 'cron(0 18 * * ? *)' \
--schedule-expression-timezone 'Asia/Tokyo' \
--flexible-time-window '{"Mode":"OFF"}' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/EventBridgeSchedulerStopEC2Role",
"Arn": "arn:aws:scheduler:::aws-sdk:ec2:stopInstances",
"Input": "{\"InstanceIds\":[\"i-0123456789abcdef0\"]}",
"DeadLetterConfig": {
"Arn": "arn:aws:sqs:ap-northeast-1:123456789012:scheduler-dlq"
}
}'
DLQにFIFOキューは使えません。
EventBridge SchedulerのDLQにはSQS標準キューを使います。
CLIで作る場合の例
コンソール操作をコード化したい場合は、AWS CLIでも作成できます。
次の例は、毎日18時に東京リージョンのEC2を停止するスケジュールです。実行前に、ロールARN、アカウントID、インスタンスIDを自分の環境へ置き換えてください。
# 毎日18時にEC2停止APIを呼び出すスケジュールを作成する
aws scheduler create-schedule \
--region ap-northeast-1 \
--name stop-ec2-at-1800 \
--schedule-expression 'cron(0 18 * * ? *)' \
--schedule-expression-timezone 'Asia/Tokyo' \
--flexible-time-window '{"Mode":"OFF"}' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/EventBridgeSchedulerStopEC2Role",
"Arn": "arn:aws:scheduler:::aws-sdk:ec2:stopInstances",
"Input": "{\"InstanceIds\":[\"i-0123456789abcdef0\"]}"
}'
作成後の確認例です。
# スケジュールの有効状態、cron式、タイムゾーンを確認する
aws scheduler get-schedule \
--region ap-northeast-1 \
--name stop-ec2-at-1800 \
--query '{State:State,Expression:ScheduleExpression,Timezone:ScheduleExpressionTimezone,TargetArn:Target.Arn,RoleArn:Target.RoleArn}'
EC2停止権限だけ先に確認したい場合は、EC2 APIのdry-runも使えます。dry-runは、権限がある場合でも DryRunOperation というエラー形式で返る点に注意します。
# 実際には停止せず、StopInstancesを呼べる権限があるか確認する
aws ec2 stop-instances \
--region ap-northeast-1 \
--instance-ids i-0123456789abcdef0 \
--dry-run
停止済みEC2に実行されたらどうなるか
この構成では、毎日18時に StopInstances を呼び出します。
EC2が起動中なら停止へ進みます。すでに停止済みのEC2に対しても、通常は「毎回、事前に起動状態を判定するLambda」を作るより、まずシンプルに StopInstances を投げる構成で十分なことが多いです。
ただし、運用では次を確認しておくと安心です。
| 確認項目 | 見る理由 |
|---|---|
| スケジュールの実行履歴 | 18時にSchedulerが動いたか |
| EC2の状態遷移 |
running から stopped へ変わったか |
| CloudTrail |
StopInstances APIが呼ばれたか |
| Schedulerの失敗メトリクス | IAM権限不足や入力JSONミスがないか |
停止済みEC2に対して何度も StopInstances を投げる設計が気になる場合は、Lambda経由にして状態判定を入れる方法もあります。
ただ、この記事の目的は「検証用EC2の停止忘れを減らす最小構成」なので、まずは固定IDへ直接停止APIを投げる形で整理しています。
注意点
停止は削除ではない
EC2の停止は削除ではありません。停止時は、通常はOSの正常なシャットダウンが試行されます。
EBS-backed EC2では、停止後もルートボリュームやデータボリュームは残ります。EC2のインスタンス使用料は止まっても、EBSボリュームなどの料金は残る点に注意します。
また、EC2に自動割り当てされたパブリックIPv4アドレスは停止で失われます。
Elastic IPを関連付けている場合は、停止中もElastic IPが残り、料金確認の対象になります。
instance store-backedインスタンスは停止できません。検証環境を自動停止したい場合は、EBS-backed EC2かどうかを先に確認してください。
Auto Scalingグループ配下は別扱いにする
Auto Scalingグループ配下のEC2を手動またはスケジュールで直接停止すると、Auto Scaling側が異常と判断し、別インスタンスに置き換えることがあります。
この場合は、EC2単体の StopInstances ではなく、Auto Scalingグループの スケジュールされたスケーリング を使います。
例えば、夜間に検証環境を0台へ落とすなら、次のような考え方です。
| 時刻 | 操作 |
|---|---|
| 9:00 | desired capacityを1へ戻す |
| 18:00 | desired capacityを0へ下げる |
最小キャパシティが1のままだとdesired capacityを0にできないため、必要に応じて最小、希望、最大の値をセットで見直します。
本番環境では止める前に確認する
本番EC2を止める場合は、単にスケジュールを作るだけでは危険です。
- ALBやRoute 53から切り離される設計か
- バッチ処理やジョブが途中で止まらないか
- 監視アラートが大量に出ないか
- 起動手順、復旧手順があるか
- 停止してよい時間帯が合意されているか
検証環境なら簡単な設定で済むこともありますが、本番環境ではレビューを通してから設定します。
実務で見るポイント
- スケジュール名に対象と時刻を入れる。例:
stop-ec2-at-1800 - IAMロールは対象EC2のARNに絞る
- 初回は5分後などでテストしてから本番時刻に戻す
- 共有環境ではCloudWatchメトリクスやDLQで失敗を拾えるようにする
- Auto Scalingグループ配下ならEC2単体停止ではなくスケジュールされたスケーリングを使う
- 停止後もEBS料金は残るため、コスト削減額を過大評価しない
- 停止してよい環境かをタグや命名で分かるようにする
試験で意識する観点
AWS資格学習では、次の切り分けが問われやすいです。
| 観点 | 覚え方 |
|---|---|
| 定時にAWS APIを呼ぶ | EventBridge Scheduler |
| 条件分岐や対象検索が必要 | Lambdaなどの処理を挟む |
| Auto Scalingグループの台数を時間で変える | スケジュールされたスケーリング |
| EC2停止後のデータ | EBSは残るが、インスタンス使用料とは別に料金が残る |
| 権限 | Scheduler実行ロールにターゲットAPIの権限が必要 |
| 失敗確認 | CloudWatchメトリクス、CloudTrail、必要ならDLQ |
関連記事
- AWSインフラ工程を5ステップで整理する
- AWS CloudFormation前編 IaC・YAML・スタック・疎結合
- AWS CLIでAuto Scaling グループの「希望する容量、最小キャパシティ、最大キャパシティ」を変更する
参考・確認先
- Using universal targets in EventBridge Scheduler
- Schedule types in EventBridge Scheduler
- Setting up Amazon EventBridge Scheduler
- Confused deputy prevention in EventBridge Scheduler
- Configuring a schedule's dead-letter queue in EventBridge Scheduler
- Troubleshooting Amazon EventBridge Scheduler
- StopInstances - Amazon EC2 API Reference
- Amazon EC2 IAM policy example: start or stop a specific instance
- Troubleshoot unhealthy instances in Amazon EC2 Auto Scaling
- Scheduled scaling for Amazon EC2 Auto Scaling
まとめ
- 1台または数台のEC2停止なら、EventBridge Schedulerから
StopInstancesを直接呼ぶ構成が簡単 - 毎日18時なら、タイムゾーン
Asia/Tokyo、cron式0 18 * * ? * - Lambdaは、対象検索、通知、条件分岐が必要になってから検討する
- 共有環境ではCloudWatchメトリクスやDLQも設定し、失敗を見逃さない
- Auto Scalingグループ配下は、EC2単体停止ではなくスケジュールされたスケーリングを使う
- 停止後もEBS料金は残るため、コスト削減の見積もりではそこまで見る
おわりに
Wealthy Designでは、AWSやGCPを使った検証環境づくり、運用改善、技術記事化にも取り組んでいます。会社の取り組みは、会社サイトにまとめています。