ググれば似たようなコードはあると思いますが、忘備録として残しています。
AWS Instance Schedulerを利用したり、タグに時間を設定しLambdaの定期実行でその時間が来れば停止するといったコードはよく見かけたのですが、コストを最大に下げるためにLambda実行回数も減らしたかったので、時間固定を前提としました。
やりたいこと
EC2インスタンスのタグで下記のように設定したインスタンスの自動停止を平日21時に実行したい。
- Name:
auto-stop
- Value:
true
手順
IAMロール・ポリシーの作成
こういうポリシーを持つIAMロールを作っておく
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StopInstances",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
CloudWatch Eventsの設定
毎晩21時に自動でシャットダウンしたいので
cron(0 12 ? * MON-FRI *)
と設定する。時間はUTCなのでJSTをUTCに変換して設定することに注意。
Lambdaの作成
上記のIAMロール・CloudWatch Eventsを指定しLambdaを作成する。
実行時間はデフォルト3秒だけど足りないので1分ぐらいに設定する。
ランタイムはPython3.8です。
import json
def lambda_handler(event, context):
import boto3
ec2 = boto3.client('ec2')
# 対象のEC2インスタンスIDsを取得
instances = targetInstances(ec2,'auto-stop', 'true')
if len(instances) != 0:
print("--- stop instances ---")
print(instances)
# 停止
ec2.stop_instances(InstanceIds=instances)
# 対象のEC2インスタンスIDsを取得
def targetInstances(ec2, tag_name, tag_value):
query = [
{"Name": "instance-state-name", "Values": ["running"]},
{'Name': 'tag-key', "Values": [tag_name]},
]
fetch_instances = ec2.describe_instances(Filters=query)['Reservations']
instances = []
for i in fetch_instances:
for tags in i['Instances'][0]['Tags']:
if tag_name in tags['Key']:
if tags['Value'] == tag_value:
instanceId = i['Instances'][0]["InstanceId"]
instances.append(i['Instances'][0]["InstanceId"])
return(instances)
#まとめ
開発環境用のEC2インスタンスはこまめに落として、インスタンス代を節約しましょう。
自動起動もやりたい場合は、ポリシーにec2:StartInstances
を追記して、新規に開始時間を設定したCloudwatch Eventsを作成し、Lambdaを作成し上記コードを起動用に書き換えればいけます。