LoginSignup
6
4

More than 3 years have passed since last update.

EC2をタグに基づいて、特定の時間に自動で起動/停止する

Last updated at Posted at 2019-07-24

概要

いったい何番煎じだよという感じですが、Lambda上にデプロイしたコードから、EC2のインスタンスを定期的に起動/停止させます。

今の時代、こちらの記事にある通り、プログラムを書かずともLambdaの定期起動/停止ができてしまいます。
それでも、本記事のコードをデプロイした後であれば、EC2インスタンスを立てるたびにCloudWatchの設定をいじる必要もなく、インスタンスにタグを追加するだけで自動起動/停止の設定ができるようになり、便利です。

Lambdaの設定

本記事のコードは、EC2に設定されているタグを見て、インスタンスの起動/停止を行います。そのため、自動設定対象にしたいEC2インスタンスには、以下のようにstart-time,stop-timeのタグをつけます。それぞれ、起動時間と停止時間をHHMM形式で表します。
無題.png

コード

以下のPythonのコードを、Lambdaにデプロイします。もちろん、LambdaにはEC2を起動や停止するための、適当なIAMロールをつけます。

manage_ec2.py
import boto3;
import datetime;

# 最初に呼ばれる関数
def lambda_handler(event, context):
    client = boto3.client('ec2', 'ap-northeast-1')
    # boto3でec2の全インスタンスの情報を取得
    response = client.describe_instances()
    # 必要な情報のみを抜き出したリストを作成
    instance_list = extract_instance_info(response)
    # 上のリストを基に、必要であればインスタンスを起動/停止する
    manage_instances(instance_list,client)

# ec2インスタンスのリストを作成
def extract_instance_info(response):
    return_val = []
    for instance_data in response['Reservations'][0]['Instances']:
        try:
            tmp = {}
            # インスタンスのid
            tmp['id'] = instance_data['InstanceId']
            # タグで指定されている起動時間
            tmp['start_time'] = convert_time([tag['Value'] for tag in instance_data['Tags'] if tag['Key'] == 'start-time'][0])
            # タグで指定されている終了時間
            tmp['stop_time'] = convert_time([tag['Value'] for tag in instance_data['Tags'] if tag['Key'] == 'stop-time'][0])
            # 現在のインスタンスの起動状況
            tmp['status'] = instance_data['State']['Name']
            return_val.append(tmp)
        except (KeyError, ValueError, TypeError) as err:
            print(err)
            # かなり乱暴なのは承知ですが、自動起動/停止対象外のインスタンス(タグが設定されていないもの)があれば、例外を発生させて無視します
            continue
    print(return_val)
    return return_val

# タグで指定されている起動/停止時間を、datetime.time型に変換
def convert_time(str_time):
    hour = int(str_time[:2])
    min = int(str_time[2:4])
    return datetime.time(hour,min)

# インスタンスの起動/停止を行う
def manage_instances(instance_list,client):
    # 現在時刻をdatetime.time型で取得
    current_time = datetime.datetime.now().time()
    for instance in instance_list:
        # インスタンス停止中で、起動時間を過ぎていれば、インスタンスを立ち上げる
        if instance['status'] != 'running' and current_time >= instance['start_time']:
            response = client.start_instances(
                InstanceIds=[
                    instance['id']
                ]
            )
            print(response)
        # インスタンス起動中で、停止時間を過ぎていれば、インスタンスを停止する
        elif instance['status'] == 'running' and current_time <= instance['stop_time']:
            response = client.stop_instances(
                InstanceIds=[
                    instance['id']
                ]
            )
            print(response)
        else:
            # 何もすることないけど、ログだけ出しとく
            print('no action was taken')

このコードをデプロイしたLambda関数を、CloudWatchで30分おきなどで実行させれば、完成です。

上のコードでは現在時刻を取得するコードが含まれているので、Lambdaの環境変数に、必ずTZ:Asia/Tokyoを付け加えてください。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4