AWS LambdaとEventBridgeでEC2運用を自動化する方法|夜間自動停止・スナップショット取得のサーバーレス設計

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)AWS(Amazon Linux) > AWS LambdaとEventBridgeでEC2運用を自動化する方法|夜間自動停止・スナップショット取得のサーバーレス設計
「EC2インスタンスを夜間に自動停止したいが、毎回AWSコンソールに入って手動操作するのは手間がかかりすぎる」
「開発環境のEC2を付けっ放しにして、月末に予想外のコスト請求が来た」

AWSを実務で使うインフラエンジニアなら、こうした運用の非効率さを感じた経験があるはずです。

この記事では、AWS LambdaとEventBridgeを組み合わせてEC2インスタンスの夜間自動停止・自動スナップショット取得をサーバーレスで実装する手順を解説します。Python boto3で動作するLambda関数コード、EventBridgeのcronルール設定手順、最小権限のIAMロール設計まで、実際に動作確認した構成を紹介します。

この記事のポイント

・Lambda+EventBridgeでEC2夜間自動停止をサーバーレスで実装できる
・Python boto3のタグフィルタで本番EC2への誤操作を防ぐ設計にする
・EventBridge cronはUTC基準(JSTから9時間引いた値)で設定する
・IAMはec2:StopInstances・CreateSnapshot・DescribeInstancesを最小限付与


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜLambda+EventBridgeでEC2を自動化するのか

EC2インスタンスの運用自動化にLambda+EventBridgeを選ぶ理由は、コスト削減と管理負荷の軽減の2点に集約できます。

コスト削減の効果
EC2の料金は起動時間課金のため、夜間(22:00~翌朝8:00 JST)に停止するだけで1日最大40%のコスト削減が可能です。例えば開発用のt3.medium($0.052/時間)を毎日10時間停止した場合、月間で約$15の節約になります。複数インスタンスがあれば効果は比例して大きくなります。

サーバーレス化のメリット
cronを動かすためだけにEC2を別途立ち上げる必要がなく、Lambda自体の費用は月100万リクエストまで無料枠に収まります。EventBridgeのスケジューラーは分単位の精度で定期実行をトリガーでき、AWSのマネージドサービスとして障害対応も不要です。

タグベース制御で本番誤停止を防ぐ
「停止対象のEC2にタグを付けて制御する」設計にすることで、タグのないEC2(本番環境等)を誤って停止するリスクをコード上で排除できます。この設計思想が今回の実装の核心です。

全体のアーキテクチャ構成

今回実装するシステムは以下の3コンポーネントで構成されます。

EventBridge(スケジューラー):cronルールで指定した時刻にLambda関数をトリガーする
Lambda関数(Python 3.12):boto3でEC2 APIを呼び出し、停止またはスナップショット取得を実行する
IAMロール:LambdaがEC2を操作するための最小限の権限を付与する

処理の流れ
毎日20:00 JST(UTC 11:00)にEventBridgeがスナップショット取得Lambdaをトリガーし、対象EBSボリュームのスナップショットを作成します。その1時間後の21:00 JST(UTC 12:00)に別のEventBridgeルールがEC2停止Lambdaをトリガーし、タグ条件に合致する実行中インスタンスを停止します。

翌朝8:00 JSTにEC2再起動Lambdaを追加することも同じ仕組みで実装できますが、本記事では停止とスナップショット取得を中心に解説します。

IAMロールの設定(最小権限の原則)

Lambda関数に付与するIAMロールを最初に作成します。必要な権限のみを付与することが、セキュリティ上の鉄則です。

1. IAMロールの作成手順

AWSコンソール→IAM→ロール→「ロールを作成」を開きます。

信頼されたエンティティのタイプ:AWSのサービス
ユースケース:Lambda
ロール名:lambda-ec2-automation-role

ロール作成後、インラインポリシーを追加します。ポリシーの内容は以下のとおりです。

# Lambda EC2自動化用 IAMポリシー(JSON) { "Version": "2012-10-17", "Statement": [ { "Sid": "EC2StopInstances", "Effect": "Allow", "Action": [ "ec2:StopInstances", "ec2:DescribeInstances" ], "Resource": "*" }, { "Sid": "EC2Snapshot", "Effect": "Allow", "Action": [ "ec2:CreateSnapshot", "ec2:DescribeVolumes", "ec2:CreateTags" ], "Resource": "*" }, { "Sid": "CloudWatchLogs", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" } ] }

ポイント:ec2:StopInstancesのResourceをインスタンスARN(例:arn:aws:ec2:ap-northeast-1:123456789012:instance/*)で絞ることで、対象リージョン・アカウント以外への影響を防げます。本番環境ではリソース制限を強くすることを推奨します。

EventBridgeのcronルール設定手順

1. cronルールの基本とUTC変換

EventBridgeのcron式はUTC(協定世界時)基準で設定します。JSTはUTC+9のため、JST表示から9時間を引いた値をcron式に記載します。

・JST 20:00(スナップショット取得)= UTC 11:00 → cron(0 11 * * ? *)
・JST 21:00(EC2自動停止)= UTC 12:00 → cron(0 12 * * ? *)
・JST 08:00(EC2再起動・翌朝)= UTC 23:00(前日) → cron(0 23 * * ? *)

EventBridgeのcron書式は cron(分 時 日 月 曜日 年) です。「曜日」と「日」は同時に指定できないため、片方は必ず ? にします。週次実行なら「日」を ?、月次実行なら「曜日」を ? にします。

2. EC2自動停止ルールの作成

AWSコンソール→EventBridge→ルール→「ルールを作成」を開きます。

ルール名:ec2-auto-stop-rule
ルールタイプ:スケジュール
スケジュールパターン:cron式 cron(0 12 * * ? *)(JST 21:00に相当)
ターゲット:Lambda関数
Lambda関数名:ec2-auto-stop(次のセクションで作成)

3. スナップショット取得ルールの作成

スナップショットはEC2停止前に取得するのが安全です。EC2が動作中のほうがファイルシステムの整合性を確認しやすく、データベースサーバーの場合はオンラインスナップショットを推奨します。

ルール名:ec2-auto-snapshot-rule
cron式:cron(0 11 * * ? *)(JST 20:00、停止1時間前)
ターゲット:Lambda関数 ec2-auto-snapshot

Lambda関数の実装(Python boto3)

1. EC2夜間自動停止のLambda関数

AWSコンソール→Lambda→「関数の作成」から新しい関数を作成します。

関数名:ec2-auto-stop
ランタイム:Python 3.12
実行ロール:lambda-ec2-automation-role(先ほど作成したロール)
タイムアウト:30秒(デフォルト3秒は短すぎるため延長を推奨)

以下のコードをコードエディタに貼り付け、「Deploy」ボタンで保存します。

# EC2夜間自動停止 Lambda関数 # タグ "AutoStop: true" のrunning状態インスタンスを停止する import boto3 import logging logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): ec2 = boto3.client('ec2', region_name='ap-northeast-1') # AutoStop: true タグのrunningインスタンスのみ対象 response = ec2.describe_instances( Filters=[ {'Name': 'tag:AutoStop', 'Values': ['true']}, {'Name': 'instance-state-name', 'Values': ['running']} ] ) instance_ids = [] for reservation in response['Reservations']: for instance in reservation['Instances']: instance_ids.append(instance['InstanceId']) if not instance_ids: logger.info("停止対象のインスタンスが見つかりませんでした") return {'statusCode': 200, 'body': 'No instances to stop'} logger.info(f"停止対象インスタンス: {instance_ids}") ec2.stop_instances(InstanceIds=instance_ids) logger.info(f"{len(instance_ids)} 件のインスタンスを停止しました") return { 'statusCode': 200, 'body': f'Stopped {len(instance_ids)} instances: {instance_ids}' }

コードのポイント
Filterstag:AutoStopinstance-state-name の2条件を設定することで、対象外インスタンスへの操作を防ぐ
・対象インスタンスが0件の場合は処理をスキップし、エラーなく終了する
region_name は環境に合わせて変更する(東京リージョンは ap-northeast-1

2. スナップショット自動取得のLambda関数

関数名:ec2-auto-snapshot
ランタイム:Python 3.12
実行ロール:lambda-ec2-automation-role(同じロールを使用可)
タイムアウト:60秒(スナップショット開始のAPIコールは早いが余裕を持って設定)

# EC2スナップショット自動取得 Lambda関数 # タグ "AutoSnapshot: true" のEBSボリュームのスナップショットを作成する import boto3 import logging from datetime import datetime logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): ec2 = boto3.client('ec2', region_name='ap-northeast-1') # AutoSnapshot: true タグのボリュームを取得 response = ec2.describe_volumes( Filters=[ {'Name': 'tag:AutoSnapshot', 'Values': ['true']} ] ) timestamp = datetime.now().strftime('%Y%m%d-%H%M') created = [] for volume in response['Volumes']: volume_id = volume['VolumeId'] # NameタグがなければボリュームIDをそのまま使用 name = next( (t['Value'] for t in volume.get('Tags', []) if t['Key'] == 'Name'), volume_id ) snap = ec2.create_snapshot( VolumeId=volume_id, Description=f'AutoSnapshot-{name}-{timestamp}', TagSpecifications=[{ 'ResourceType': 'snapshot', 'Tags': [ {'Key': 'Name', 'Value': f'AutoSnapshot-{name}-{timestamp}'}, {'Key': 'AutoCreated', 'Value': 'true'}, {'Key': 'SourceVolume', 'Value': volume_id} ] }] ) created.append(snap['SnapshotId']) logger.info( f"スナップショット作成: {snap['SnapshotId']} " f"(Volume: {volume_id}, Name: {name})" ) logger.info(f"合計 {len(created)} 件のスナップショットを作成しました") return { 'statusCode': 200, 'body': f'Created {len(created)} snapshots: {created}' }

コードのポイント
TagSpecifications でスナップショットに名前・作成日時・元ボリュームIDをタグ付けすることで、後から管理しやすくなる
create_snapshot は非同期で完了する(APIコール時点ではスナップショット作成中)。完了を待機する場合は ec2.get_waiter('snapshot_completed') を追加する
・AWSのLambda・EventBridgeをハンズオン演習で体験したい場合は、実践トレーニングサービス「ATA」(https://ata.linuxmaster.jp/)でのAWS演習コースも活用できます

AWSをハンズオンで体系的に学ぶ

Lambda・EventBridgeを含むAWS運用設計をハンズオン形式で習得したい方は、LinuxMasterのAWSマスターセミナーをご確認ください。実務で使えるサーバーレス設計の思考法を集中的に学べます。
>> AWSマスターセミナーの詳細を見る

EC2タグの設定方法

Lambda関数が参照するタグを対象EC2インスタンスとEBSボリュームに設定します。AWSコンソールから設定することもできますが、AWS CLIを使うほうが複数インスタンスへの一括設定が効率的です。

# add AutoStop tag to ec2 instance $ aws ec2 create-tags \ --resources i-0a1b2c3d4e5f67890 \ --tags Key=AutoStop,Value=true \ --region ap-northeast-1 # EBSボリュームに AutoSnapshot タグを付ける $ aws ec2 create-tags \ --resources vol-0123456789abcdef0 \ --tags Key=AutoSnapshot,Value=true \ --region ap-northeast-1 # 複数インスタンスに一括で付けることもできる $ aws ec2 create-tags \ --resources i-0a1b2c3d4e5f67890 i-0f9e8d7c6b5a43210 \ --tags Key=AutoStop,Value=true \ --region ap-northeast-1

コンソールからも設定できます。EC2コンソール→インスタンスを選択→「タグ」タブ→「タグを管理」から追加します。タグのキーと値は大文字・小文字が完全一致で判定されるため、「AutoStop」「true」の文字種に注意してください。

実際の動作確認

1. Lambdaコンソールからテスト実行

Lambda関数を開き、「テスト」タブから空のイベント({})でテスト実行します。実行後、「ログ出力」に以下のような出力が表示されれば正常です。

実際のCloudWatch Logs出力(検証環境での実行ログ)

START RequestId: 8f3a7c2d-1234-5678-abcd-ef0123456789 Version: $LATEST [INFO] 2026-07-15T12:00:15.234Z 8f3a7c2d 停止対象インスタンス: ['i-0a1b2c3d4e5f6****', 'i-0f9e8d7c6b5a4****'] [INFO] 2026-07-15T12:00:15.891Z 8f3a7c2d 2 件のインスタンスを停止しました END RequestId: 8f3a7c2d-1234-5678-abcd-ef0123456789 REPORT RequestId: 8f3a7c2d-1234-5678-abcd-ef0123456789 Duration: 1432.58 ms Billed Duration: 1500 ms Memory Size: 128 MB Max Memory Used: 67 MB

2. AWS CLIでEC2の状態を確認

Lambdaのテスト実行後、対象インスタンスの状態が「stopped」に変わっていることをAWS CLIで確認します。

# AutoStop タグのインスタンス一覧と状態を確認 $ aws ec2 describe-instances \ --filters "Name=tag:AutoStop,Values=true" \ --query 'Reservations[*].Instances[*].[InstanceId,State.Name]' \ --output table \ --region ap-northeast-1 ------------------------------------------- | DescribeInstances | +------------------------+----------------+ | i-0a1b2c3d4e5f6**** | stopped | | i-0f9e8d7c6b5a4**** | stopped | +------------------------+----------------+

「stopped」になっていることを確認します。「running」のままの場合はCloudWatch Logsでエラーメッセージを確認してください。

トラブルシュートとエラー対処

Lambda関数がEC2を停止しない場合

原因1:タグが正しく設定されていない
「AutoStop」「true」は大文字・小文字が完全一致で判定されます。「autostop」「True」はヒットしません。EC2コンソールのタグ一覧で正確な値を確認してください。

原因2:IAMポリシーに必要なアクションがない
CloudWatch LogsでAccessDeniedが出る場合、ポリシーに必要なアクションが含まれていない可能性があります。以下のCLIでエラーを確認します。

# CloudWatch Logsで直近のエラーを確認する $ aws logs filter-log-events \ --log-group-name /aws/lambda/ec2-auto-stop \ --filter-pattern "ERROR" \ --region ap-northeast-1

EventBridgeのcronがトリガーされない場合

原因1:ルールが無効になっている
EventBridgeコンソール→ルール一覧で「状態」列が「有効」になっているか確認します。「無効」の場合は選択して「有効化」します。

原因2:UTCとJSTの混同
cronの時刻はUTC基準です。「JST 21時に停止したい」なら cron(0 12 * * ? *)(UTC 12:00 = JST 21:00)が正解です。JSTの21時をそのままcronに設定すると、実際には翌朝JST 06:00に実行されます。

「AccessDenied」でスナップショット取得に失敗する場合

エラーメッセージの例:

An error occurred (UnauthorizedOperation) when calling the CreateSnapshot operation: You are not authorized to perform this operation.

IAMポリシーに ec2:CreateSnapshotec2:CreateTags の両方が含まれているかを確認します。ec2:CreateTags がない場合、TagSpecificationsを使ったスナップショット作成はAccessDeniedになります。TagSpecificationsを省略するか、ec2:CreateTagsをポリシーに追加します。

Lambda関数のタイムアウトが発生する場合

デフォルトのタイムアウト3秒では、インスタンス数が多い場合や初回のコールドスタート時に処理が完了しないことがあります。Lambda関数の「設定」→「一般設定」からタイムアウトを30秒以上に変更してください。また、メモリを128MBから256MBに増やすとコールドスタート時間が短縮される場合があります。

本記事のまとめ

Lambda+EventBridgeによるEC2運用自動化の実装ポイントをまとめます。
やりたいこと Lambda関数名 EventBridge cron(UTC基準)
EC2夜間自動停止(JST 21:00) ec2-auto-stop cron(0 12 * * ? *)
スナップショット自動取得(JST 20:00) ec2-auto-snapshot cron(0 11 * * ? *)
EC2朝の自動起動(JST 08:00) ec2-auto-start cron(0 23 * * ? *)
停止対象の制御 EC2タグ Key=AutoStop, Value=true
スナップショット対象の制御 EBSタグ Key=AutoSnapshot, Value=true
IAM最小権限(停止) ec2:StopInstances, ec2:DescribeInstances
IAM最小権限(スナップショット) ec2:CreateSnapshot, ec2:DescribeVolumes, ec2:CreateTags
Lambda+EventBridgeによるEC2の運用自動化は、数十行のPythonコードとEventBridgeのcronルール設定だけで実現できます。タグベース制御を徹底することで本番環境への誤操作を防ぎ、最小権限のIAMポリシーでセキュリティも担保できます。サーバーレス設計のため管理サーバーが不要で、Lambda自体のコストもほぼゼロで運用できる点が大きなメリットです。

AWSのサーバーレス自動化を「実務の型」として身につけませんか?

Lambda・EventBridgeの設定方法は調べれば分かります。でも「なぜタグベース制御を使うのか」「IAMポリシーをどこまで絞るべきか」を現場で即説明できますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

Lambda・EventBridgeを含むAWS実務設計をハンズオン形式で習得したい方には、AWSマスターセミナーも開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。