Python
AWS
lambda

AWS Lambda(Python)でインスタンス起動停止をSchedule実行してみる

More than 3 years have passed since last update.


はじめに

前々から作って見たかったのですが、Javaで作るとたいそうかなと思ったところ、

AWS LambdaがPythonで実行できるということで、書いたことないので、

チャレンジしようと思って、早3ヶ月。

いろんな人が書いてるなか、やってみました。


概要

DynamoDBにテーブルを作り、時間やインスタンスに設定したタグ情報、

開始か停止かを入れておく。

Lambda Function(Python)は、10分ごとに動かして、

DynamoDBに入れてるデータの時間と一致したら、

そのタグ情報が一致するインスタンス全てに対して、

開始か停止かを実行します。


準備

DynamoDBにテーブル「EC2」を作ります。

Itemは4つ。「Id」「Time」「Tag」「StartStop」。

 1. Id : シーケンス番号、順繰りになるようにしてください

 2. Time : 時間、"%H:%M"形式、例:"09:00"

 3. Tag : インスタンスのタグ開始や停止したいタグを入れてください

 4. StartStop : 開始(start)か停止(stop)かを入れてください。


Lambdaの設定


  1. Runtimeは「Python2.7」

  2. コードは後で・・・

  3. Handlerは適当に

  4. RoleはDynamoDBへの読み書きとEC2への開始/停止と参照があれば、OK

  5. メモリは128MBでいけるとおもいます

  6. タイムアウトは適当に(今回は10secにしてます)


Lambda Function(Python)

個人的に苦労した箇所がいくつかあります。

1. "Filters=[{'Name':'tag-key','Values':[tableInfo['Tag']]}]"のとこ 

"tableInfo['Tag']"の前後に"[]"がいることがわからなかった

2. "table.scan()['Items']"の"['Items']"がないといけない

これがないとDynamoDBから取得したデータのItemが取れない

3. なんでかわかりませんが、"boto3.client('ec2')"でないといけない

"boto3.resource('ec2')"だと動かなかった

4. "from boto3.dynamodb.conditions import Key, Attr"が必要みたい

で、コードは以下の通りです。

import boto3

import datetime
from boto3.dynamodb.conditions import Key, Attr

def lambda_handler(event, context):
# create EC2 client
ec2 = boto3.client('ec2')
# get the time(%H:%M)
timeInfo = datetime.datetime.now().strftime("%H:%M")
tableInfoList = getTableInfoList(timeInfo)
instanceList = getInstanceStartStopList(ec2, tableInfoList)
executeInstanceStartStop(ec2, instanceList)

# get the list of data (Id, StartEnd, Tag, Time)
# Id : Sequence
# StartEnd : "start" or "stop"
# Tag : Tag-key
# Time : %H:%M ex) 09:00
# @param timeInfo
# @return list of data(Id, StartEnd, Tag, Time)
def getTableInfoList(timeInfo):
dynamodb = boto3.resource('dynamodb')
#Set TableName
table = dynamodb.Table('EC2')
#Send the Query
#Query Parameter
# @param TimeInfo : [hh:mm]
#TimeInfo = "09:00"
tableInfoList = table.scan(
FilterExpression=Attr('Time').eq(timeInfo)
)['Items']
return tableInfoList

# get the list of data (Start or Stop Instance Ids)
# @param ec2
# @param tableInfoList
# @return instanceList Dictionaly('start', 'stop')
def getInstanceStartStopList(ec2, tableInfoList):
startInstanceIdList = []
stopInstanceIdList = []
for tableInfo in tableInfoList:
for reservation in ec2.describe_instances(Filters=[{'Name':'tag-key','Values':[tableInfo['Tag']]}])["Reservations"]:
for instance in reservation["Instances"]:
if (tableInfo['StartStop'] == 'start'):
startInstanceIdList.append(instance["InstanceId"])
elif (tableInfo['StartStop'] == 'stop'):
stopInstanceIdList.append(instance["InstanceId"])
instanceList = {"start":startInstanceIdList, "stop":stopInstanceIdList}
return instanceList

# Start of Stop Instances
# @param ec2
# @param instanceList
def executeInstanceStartStop(ec2, instanceList):
startInstanceIdList = instanceList["start"]
stopInstanceIdList = instanceList["stop"]

if not len(startInstanceIdList) == 0:
ec2.start_instances(InstanceIds=startInstanceIdList)

if not len(stopInstanceIdList) == 0:
ec2.stop_instances(stopInstanceIdList)

トライアンドエラーでなんとかできました。


これから

これからは、これに付随したものを作っていこうと思ってます。


  1. DynamoDBのデータを登録/更新/削除/閲覧できるスクリプト

  2. S3で静的HTML + JSでDynamoDBのデータを登録/更新/削除/閲覧

  3. API Gateway + Lambda で リアルタイム実行

いつになるかはわかりませんが。。。