下記を参考にして、CloudWatch+Lambdaの組み合わせを用いて、タグ指定でインスタンスの開始、停止を実装してみた。
できるだけシンプルな仕組みで簡単にEC2の自動起動・停止を実現したい!
AWS Lambda+Python3で複数のRDSを起動停止
開発環境など業務時間内のみインスタンスを稼働させ、コストを最小化させたいときに役に立つ。
EC2インスタンスの場合
Lambda関数に設定する実行ロール
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "ec2:StartInstances", "ec2:StopInstances" ], "Resource": "*" } ] }
Lambda関数(ec2.describe_instances()の戻りデータがそれなりに大きいので、タイムアウトをデフォルトの3秒より少し長めにしておかないとタイムアウトしてしまう)
import boto3 """ Request 4Parameters Region Action(start or stop) TagName TagValue """ def lambda_handler(event, context): region = event['Region'] action = event['Action'] tagname = event['TagName'] tagvalue = event['TagValue'] ec2 = boto3.client('ec2', region_name=region) try: reservations = ec2.describe_instances() except Exception as e: print(e) return { 'status': -1 } if action == 'start': for instances in reservations["Reservations"]: for instance in instances['Instances']: tags = instance['Tags'] tag = next(iter(filter(lambda tag: tag['Key'] == tagname and tag['Value'] == tagvalue, tags)), None) if tag: if instance['State']['Name'] == 'stopped': response = ec2.start_instances(InstanceIds=[instance["InstanceId"]]) print(instance['InstanceId'] + " is starting!") else: print(instance['InstanceId'] + " is already started!") elif action == 'stop': for instances in reservations["Reservations"]: for instance in instances['Instances']: tags = instance['Tags'] tag = next(iter(filter(lambda tag: tag['Key'] == tagname and tag['Value'] == tagvalue, tags)), None) if tag: if instance['State']['Name'] == 'running': response = ec2.stop_instances(InstanceIds=[instance["InstanceId"]]) print(instance['InstanceId'] + " is stopping!") else: print(instance['InstanceId'] + " is already stopped!") return { 'status': 0 }
CloudWatchEventで設定するターゲットの入力値(定数 (JSON テキスト))
{ "Action": "start", "Region": "ap-northeast-1", "TagName": "AutoStart", "TagValue": "true" }
上記を設定すると、東京リージョン(ap-northeast-1)にあるAutoStart=Trueとタグ設定されたEC2インスタンスが起動するようになります。Actionをstopとすると停止になります。
RDSインスタンスの場合
Lambda関数に設定する実行ロール
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "rds:DescribeDBInstances", "rds:StopDBInstance", "rds:StartDBInstance", "rds:ListTagsForResource" ], "Resource": "*" } ] }
Lambda関数
import boto3 """ Request 4Parameters Region Action(start or stop) TagName TagValue """ def lambda_handler(event, context): region = event['Region'] action = event['Action'] tagname = event['TagName'] tagvalue = event['TagValue'] rds = boto3.client('rds', region_name=region) try: dbs = rds.describe_db_instances() except Exception as e: print(e) return { 'status': -1 } if action == 'start': for db in dbs['DBInstances']: instance_arn = db['DBInstanceArn'] instance_tags = rds.list_tags_for_resource(ResourceName=instance_arn) tags = instance_tags['TagList'] tag = next(iter(filter(lambda tag: tag['Key'] == tagname and tag['Value'] == tagvalue, tags)), None) if tag: if db['DBInstanceStatus'] == 'stopped': response = rds.start_db_instance(DBInstanceIdentifier=db["DBInstanceIdentifier"]) print(db['DBInstanceIdentifier'] + " is starting!") else: print(db['DBInstanceIdentifier'] + " is already started!") elif action == 'stop': for db in dbs['DBInstances']: instance_arn = db['DBInstanceArn'] instance_tags = rds.list_tags_for_resource(ResourceName=instance_arn) tags = instance_tags['TagList'] tag = next(iter(filter(lambda tag: tag['Key'] == tagname and tag['Value'] == tagvalue, tags)), None) if tag: if db['DBInstanceStatus'] == 'available': response = rds.stop_db_instance(DBInstanceIdentifier=db["DBInstanceIdentifier"]) print(db['DBInstanceIdentifier'] + " is stopping!") else: print(db['DBInstanceIdentifier'] + " is already stopped!") return { 'status': 0 }
参考)EC2とRDSのAPIに差異がある点に注意が必要。
例:EC2のstart_instancesは、リストで渡せる(Type: Array of strings)一方で、RDSのstart-db-instanceは、単一のIDしか渡せない(Type: String/リストで渡せない)。