自動停止EC2ホストを作る 改良編
前回の続きです。
今、特定のインスタンスIDを停止するlambda関数を作って起動している状態です。
とりあえず5分に一度ぶん回っているのでその辺の調整から。
cloudwatch → イベント ルール → で、前回作成したstopSpecifiedEc2
とかいうやつを無効化しときます。
関数を修正する
現状がこれです。で、よくみたらStopSpeficiedEc2Instance
ってスペルミスってますね。まあいいか…
1import boto3
2region = 'ap-northeast-1' # これと
3# instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
4instances = ['i-0f6361d406ce4e986'] # これ
5ec2 = boto3.client('ec2', region_name=region)
6
7def lambda_handler(event, context):
8 ec2.stop_instances(InstanceIds=instances)
9 print('stopped your instances: ' + str(instances))
まず、「特定の」インスタンスじゃなく、これを柔軟に返せるように関数化しときましょう。
1import boto3
2region = 'ap-northeast-1'
3ec2 = boto3.client('ec2', region_name=region)
4
5def get_instances():
6 return ['i-0f6361d406ce4e986']
7
8
9def lambda_handler(event, context):
10 instances = get_instances()
11 return instances
12 # ec2.stop_instances(InstanceIds=instances)
13 # print('stopped your instances: ' + str(instances))
get_instancesではまだ特定のインスタンスIDをべたで打ってますが、この関数を改良化していけばいいという事になりますよね。
インスタンスIDをベタ打ちせずフィルタで取得する
現状 i-0f6361d406ce4e986
というインスタンスIDをベタでやってますが、タグで検索してくるようにします。ここではautostop
というタグを貼る事にします
このautostop(に1と設定された)タグが貼られたインスタンスを取得します。何なら2つくらい用意してもよいでしょう。ここでは2つのインスタンスを起動する事にしました。
現状ではこうなっています。
さて、lambdaを編集してこれを取れるようにし、たいのですが、実は権限が足りておりません。これは特定のインスタンスIDを取得する事は出来るんですが、バーっとサーチするには
1ec2:DescribeInstances
という権限が必要となります。という事はポリシーを変更する必要があります。
前段で作成したEC2StartStop
というポリシーを編集します。
ec2:DescribeInstances
を付けました。これでコードに戻ります。
pythonズブの素人が頑張ってインスタンスIDを取得する
https://dev.classmethod.jp/articles/describe_instances_without_reservations_by_boto3/
これを多いに参考にしました。
1import boto3
2import pprint
3region = 'ap-northeast-1'
4ec2 = boto3.client('ec2', region_name=region)
5
6def get_instances():
7 response = ec2.describe_instances()
8 instances = sum([reservation['Instances'] for reservation in response['Reservations']], [])
9 for instance in instances:
10 pprint.pprint(instance['InstanceId'])
11
12def lambda_handler(event, context):
13 instances = get_instances()
14 return instances
15
これで一応
1'i-0f6361d406ce4e986'
2'i-0795c85d8f210161e'
3'i-08b4196526beb9c6f'
ってのが却ってきました。
このコードをもう少しpythonっぽく書きますた。
1def get_instances():
2 response = ec2.describe_instances()
3 instance_list = sum([reservation['Instances'] for reservation in response['Reservations']], [])
4 instances = [instance['InstanceId'] for instance in instance_list]
5 pprint.pprint(instances)
さて、ここにfilterをいれるゾイ
1def get_instances():
2 # autostopが「1」に設定されているものを取る
3 response = ec2.describe_instances(Filters=[{'Name':'tag:autostop','Values':['1']}])
4 instance_list = sum([reservation['Instances'] for reservation in response['Reservations']], [])
5 instances = [instance['InstanceId'] for instance in instance_list]
6 pprint.pprint(instances)
すると
1['i-0f6361d406ce4e986', 'i-08b4196526beb9c6f']
と2つになりました。さらに起動中の判定も入れときます。
1def get_instances():
2 response = ec2.describe_instances(
3 Filters=[
4 {'Name':'tag:autostop','Values':['1']},
5 {'Name':'instance-state-name','Values':['running']}
6 ]
7 )
8 instance_list = sum([reservation['Instances'] for reservation in response['Reservations']], [])
9 instances = [instance['InstanceId'] for instance in instance_list]
10 pprint.pprint(instances)
ええやん。
あとはもう単純に止めに行きます。
1import boto3
2import pprint
3region = 'ap-northeast-1'
4ec2 = boto3.client('ec2', region_name=region)
5
6def get_instances():
7 response = ec2.describe_instances(
8 Filters=[
9 {'Name':'tag:autostop','Values':['1']},
10 {'Name':'instance-state-name','Values':['running']}
11 ]
12 )
13 instance_list = sum([reservation['Instances'] for reservation in response['Reservations']], [])
14 instances = [instance['InstanceId'] for instance in instance_list]
15 return instances
16
17
18def lambda_handler(event, context):
19 instances = get_instances()
20 ec2.stop_instances(InstanceIds=instances)
21 print('stopped your instances: ' + str(instances))
で、適当にトリガーを仕掛けます。前回を参照の事。
まあほぼこれでいいんですが…
1'LaunchTime': datetime.datetime(2020, 10, 7, 4, 36, 43, tzinfo=tzlocal()),
EC2の個々の情報のリストの中に↑みたいなのがあるので加工すれば、EC2起動してから○時間とか○分経ってれば停止、みたいな細かい事もできるでしょう、多分。。
にしても割とニーズありそうだけどコードの情報って結構ないもんですね。ある意味鍛えられますね。
あと、実行した時にメールなりで通知とかいうのもありですかね。修正点としてinstancesの数が0ならstopにかけずにreturnしたりとか…
まあ、その辺も含めて続くかもしれないし続かないかもしれない。