LambdaでEC2のタグに指定した時間で自動起動・自動停止する

EventBridgeとSSMオートメーション(またはLambda)を組み合わせて、
特定の時間にEC2を自動起動したり自動停止する機能をよく見ます。

この機能でも十分使いやすいですが、起動/停止の時間にもう少し自由度がほしいと思っていました。
時間をちょっと変更したいときもEventBridgeを変更する必要がありましたし、特定のEC2のみを変更ということができませんでした。
なので、起動と停止する時間をEC2のタグで自由に設定できるようにしてしまおうと思います。

使用例

このページのLambdaとAmazon EventBridgeを使用することで以下のようなことが実現できます。
  • EC2に設定したタグの時間で自動起動
  • EC2に設定したタグの時間で自動停止
  • タグの値を変更することで、起動・停止の時間変更
  • タグを削除することで、自動起動・自動停止の対象から除外
紹介するLambdaはEC2のタグの値を読み取って、指定した時間でEC2を起動・停止するので、
時間変更も起動・停止対象からの除外も簡単にできるのが特徴です。

構成図

紹介するLambdaはAmazon EventBridgeにて毎時00分に起動するようにcronを設定します。
 cron設定:(0 * * * ? *)

boto3関数は、EC2の「describe_instances」、「start_instances」、「stop_instances」を使用します。
これらの関数で起動状態とタグの情報を取得し、起動と停止を行うEC2インスタンスを特定します。

例えば、午前9時に起動したLambdaは「起動状態が起動」かつ「AutoStopタグが09」のEC2インスタンスを停止しつつ、
「起動状態が停止」かつ「AutoStartタグが09」のEC2インスタンスを起動する動きとなります。
この動きを毎時00分に行うようにEvent BridgeとLambdaで実現しています。

Lambdaソースコード

import boto3
from datetime import datetime, timedelta, timezone

ec2_client = boto3.client('ec2')
JST = timezone(timedelta(hours=+9), 'JST')

def lambda_handler(event, context):
    current_hour = datetime.now(JST).time().strftime('%H')
    
    #起動対象の検索(停止中かつタグ一致)
    response_start = ec2_client.describe_instances(Filters=[
            {
                'Name': 'instance-state-name',
                'Values': ['stopped'],
            },
            {
                'Name': 'tag:AutoStart',
                'Values': [current_hour]
            },
        ])
    if len(response_start["Reservations"]) > 0:
        instanceids=[]
        for i in range(len(response_start["Reservations"][0]['Instances'])):
            instanceids.append(response_start["Reservations"][0]['Instances'][i]['InstanceId'])
        #EC2起動
        ec2_client.start_instances(InstanceIds=instanceids)
    
    #停止対象の検索(起動中かつタグ一致)
    response_stop = ec2_client.describe_instances(Filters=[
            {
                'Name': 'instance-state-name',
                'Values': ['running'],
            },
            {
                'Name': 'tag:AutoStop',
                'Values': [current_hour]
            },
        ])

    if len(response_stop["Reservations"]) > 0:
        instanceids=[]
        for i in range(len(response_stop["Reservations"][0]['Instances'])):
            instanceids.append(response_stop["Reservations"][0]['Instances'][i]['InstanceId'])
        #EC2停止
        ec2_client.stop_instances(InstanceIds=instanceids)
        
    return 0
                
                

権限(IAMロール設定)

LambdaにアタッチするIAMロールに「ec2:DescribeInstances」、「ec2:StartInstances」、「ec2:StopInstances」の権限を付与してください。

解説

紹介したLambdaのフローは以下の通りです。
  1. 現在時刻からタグで検索する値を取得
  2. 起動対象のEC2インスタンスの検索
  3. 対象の起動
  4. 停止対象のEC2インスタンスの検索
  5. 対象の停止
このLambdaは毎時00分に実行するようにEventBridgeを設定し、その時間で起動・停止するようタグがつけられているEC2を処理します。
00:00 AutoStartタグが00を起動/AutoStopタグが00を停止
01:00 AutoStartタグが01を起動/AutoStopタグが01を停止
・・・
22:00 AutoStartタグが22を起動/AutoStopタグが22を停止
23:00 AutoStartタグが23を起動/AutoStopタグが23を停止

EC2インスタンスのタグをもとに起動停止の対象かを判断するため、
時間を変更したいときや対象外としたいときもタグを変更すればすぐに可能です。

EC2に設定するタグ名も「'Name': 'tag:AutoStart'」と「'Name': 'tag:AutoStop',」の部分を変更すれば好きなもの変更可能です。