EC2インスタンス、RDSインスタンスを指定時間に起動及び停止する

下記を参考にして、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/リストで渡せない)。

カテゴリーAWS

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です