概要
いったい何番煎じだよという感じですが、Lambda上にデプロイしたコードから、EC2のインスタンスを定期的に起動/停止させます。
今の時代、こちらの記事にある通り、プログラムを書かずともLambdaの定期起動/停止ができてしまいます。
それでも、本記事のコードをデプロイした後であれば、EC2インスタンスを立てるたびにCloudWatchの設定をいじる必要もなく、インスタンスにタグを追加するだけで自動起動/停止の設定ができるようになり、便利です。
Lambdaの設定
本記事のコードは、EC2に設定されているタグを見て、インスタンスの起動/停止を行います。そのため、自動設定対象にしたいEC2インスタンスには、以下のようにstart-time
,stop-time
のタグをつけます。それぞれ、起動時間と停止時間をHHMM
形式で表します。
コード
以下のPythonのコードを、Lambdaにデプロイします。もちろん、LambdaにはEC2を起動や停止するための、適当なIAMロールをつけます。
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
を付け加えてください。