EC2の自動起動・停止を実現したい!
上記記事の改良版です。上記記事では自動起動・停止をhour単位でしか指定できず、一日に一度しか指定できませんでした。
それに加えて今回は
- 時刻まで指定できる(10分ごと)
- 複数時刻を指定できる
- 平日指定できる
の機能を追加しました。
今回はLambdaを何度も呼び出したくないので10分ごとにしましたが、Lambdaを毎分呼び出せば、分指定までできるようになります。
EC2のタグの設定
タグはこの様に設定します。
これだと
平日16時30分に起動して16時40分に停止する。
平日16時50分に起動して17時00分に停止する。
という流れになります。
時刻はカンマ区切りで記入して、0埋めで記載します 05:10
のような形です。
Lambda
import json
import boto3
from datetime import datetime, timedelta, timezone
# 10分単位で時間を丸める
# 例 12時8分 → 12時10分 5時58分 → 6時00分
def hour_rounder(t):
return (t.replace(second=0, microsecond=0, minute=0, hour=t.hour) + timedelta(minutes=round(t.minute, -1)//10) * 10)
# 平日ならTrueを返し、週末(土日)ならFalseを返す
# 祝日は現在考慮していない
def is_weekday(t):
weekday = t.weekday()
if weekday == 5 or weekday == 6:
return False
return True
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name='ap-northeast-1')
JST = timezone(timedelta(hours=+9), 'JST')
now = datetime.now(JST)
rounded_time = hour_rounder(now)
is_weekday_flag = is_weekday(rounded_time)
time = rounded_time.strftime("%H:%M")
# 停止するインスタンスの処理
custom_filter = [{
'Name':'tag:auto_stop_at',
'Values': ["*" + time + "*"]
}]
response = ec2.describe_instances(Filters=custom_filter)
stop_instance_ids = []
for instance_dic in response['Reservations']:
stop_instance_ids.append(instance_dic['Instances'][0]['InstanceId'])
if stop_instance_ids:
ec2.stop_instances(InstanceIds=stop_instance_ids)
# 開始するインスタンスの処理
custom_filter = [{
'Name':'tag:auto_start_at',
'Values': ["*" + time + "*"]
}]
custom_filter.append({
'Name':'tag:auto_start_only_weekly',
'Values': ['true']
})
response = ec2.describe_instances(Filters=custom_filter)
start_instance_ids = []
for instance_dic in response['Reservations']:
for tag in instance_dic['Instances'][0]['Tags']:
# 平日の場合、平日設定のインスタンスのみ起動する
if is_weekday_flag and tag['Key'] == 'auto_start_only_weekly' and tag['Value'] == 'true':
start_instance_ids.append(instance_dic['Instances'][0]['InstanceId'])
if start_instance_ids:
ec2.start_instances(InstanceIds=start_instance_ids)
return {
'statusCode': 200,
'start_instance_ids': start_instance_ids,
'stop_instance_ids': stop_instance_ids
}
かんたんにコードを説明すると
hour_rounder
という関数で、時間の10分を丸めています。
12時8分 → 12時10分 5時58分 → 6時00分
という形です。
これは考慮いらない気もしますが、毎度ピッタリの時刻にLambdaが呼ばれない可能性を考慮しています。
for instance_dic in response['Reservations']:
for tag in instance_dic['Instances'][0]['Tags']:
# 平日の場合、平日設定のインスタンスのみ起動する
if is_weekday_flag and tag['Key'] == 'auto_start_only_weekly' and tag['Value'] == 'true':
start_instance_ids.append(instance_dic['Instances'][0]['InstanceId'])
次に上記部分です。自動起動を平日のみ設定のものの考慮です。
時間からインスタンスIDをフィルタリングしたあとに、平日のみ設定だったら曜日判定するという流れです。
このあたり、もう少し簡略化できるかもしれませんが、一旦これで問題ないのでこうしています。
問題点
現状のコードだと05:00
のように0埋めで時間を入力しておく必要があります。カンマ区切りで入力できるようにした関係で、インスタンスIDを取る際に、*5:00*
というワイルドカードを使っている関係で、0がないと5:00
とすると15時にも動いてしまいます。
このあたりなんとかしたいのですが、一旦運用でカバーしています。