Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@danishi

AWS ChaliceでEC2とRDSを自動で起動停止するLambdaを作成

任意のタグが付いたEC2、RDSインスタンスをスケジュールで起動停止するためのLambdaです。

Chaliceで作ってあるのでハンドラーを変えればAPIエンドポイントから実行したりもできます。

以下実装です。

「AutoStartStop」タグが付けられたインスタンスを対象にして、平日の10時に起動、平日の19時に停止します。

app.py
from chalice import Chalice
import logging
import os
import boto3

app = Chalice(app_name='schedule-startstop')
app.log.setLevel(logging.DEBUG)

env_dryrun = False if os.environ['DRYRUN'].upper() == 'FALSE' else True


def change_instances_state(event, state='Start', dryrun=True):

    rds = boto3.client('rds')
    ec2 = boto3.client('ec2')

    if state == 'Stop':  # 停止させる条件
        filter_ec2_instance_state = 'running'
        filter_rds_instance_state = 'available'
    else:  # 起動する条件
        filter_ec2_instance_state = filter_rds_instance_state = 'stopped'

    app.log.info("Search Target EC2 Instances.")

    # 対象のEC2インスタンスを取得
    target_ec2_instances = ec2.describe_instances(
        Filters=[
            {
                'Name': 'tag-key',
                'Values': ['AutoStartStop']
            },
            {
                'Name': 'instance-state-name',
                'Values': [filter_ec2_instance_state]
            }
        ]
    ).get(
        'Reservations', []
    )

    # 対象のEC2インスタンスのIDを取得
    target_ec2_instance_ids = []
    for instances in target_ec2_instances:
        for instance in instances['Instances']:
            target_ec2_instance_ids.append(
                instance['InstanceId'])

    if len(target_ec2_instance_ids) > 0:
        try:
            # 対象のEC2インスタンスを起動or停止
            app.log.info("%s EC2 Instances:%s" %
                         (state, ",".join(target_ec2_instance_ids)))
            if state == 'Stop':
                ec2.stop_instances(
                    InstanceIds=target_ec2_instance_ids, DryRun=dryrun)
            else:
                ec2.start_instances(
                    InstanceIds=target_ec2_instance_ids, DryRun=dryrun)

        except Exception as e:
            app.log.error(e)
    else:
        app.log.info("No Target EC2 Instances.")

    app.log.info("Search Target RDS Instances.")

    # 対象のRDSインスタンスを取得
    target_rds_instances = rds.describe_db_instances().get('DBInstances', [])

    for instance in target_rds_instances:

        # タグと状態でフィルタ
        instance_state = instance['DBInstanceStatus']
        instance_tags = rds.list_tags_for_resource(
            ResourceName=instance['DBInstanceArn']).get('TagList', [])
        has_tag = next(iter(filter(
            lambda tag: tag['Key'] == 'AutoStartStop', instance_tags)), None)

        if instance_state == filter_rds_instance_state and has_tag:
            try:
                # 対象のRDSインスタンスを起動
                instance_id = instance['DBInstanceIdentifier']
                app.log.info("%s RDS Instance:%s" % (state, instance_id))

                if state == 'Stop':
                    if not dryrun:
                        rds.stop_db_instance(
                            DBInstanceIdentifier=instance_id)
                    else:
                        app.log.info("Dry run stop_db_instance.")

                else:
                    if not dryrun:
                        rds.start_db_instance(
                            DBInstanceIdentifier=instance_id)
                    else:
                        app.log.info("Dry run start_db_instance.")

            except Exception as e:
                app.log.error(e)


@app.schedule('cron(0 1 ? * MON-FRI *)')  # 平日10時起動(UTC:1時)
def cron_start_handler(event):
    change_instances_state(event, 'Start', env_dryrun)


@app.schedule('cron(0 10 ? * MON-FRI *)')  # 平日19時停止(UTC:10時)
def cron_stop_handler(event):
    change_instances_state(event, 'Stop', env_dryrun)

requirements.txt
boto3
.chalice/config.json
{
  "version": "2.0",
  "app_name": "schedule-startstop",
  "stages": {
    "dev": {
      "api_gateway_stage": "api",
      "lambda_timeout": 10,
      "environment_variables": {
        "DRYRUN": "True"
      }
    }
  }
}

このコードでは環境変数「DRYRUN」にTrueをセットして、実際に起動停止処理が走らないようにしています。
事前に狙ったインスタンスが処理対象になるか確認するのが目的です。
本当に起動停止処理を走らせる場合は「DRYRUN」にFalseをセットしてデプロイしてください。

後は処理対象にしたいEC2およびRDSのタグのKeyに(Valueは空でいいです)「AutoStartStop」を入れるだけで、時間が来たら自動で起動停止がかかります。

起動停止のタイミングを修正する場合はcron式を修正してください(UTCなので注意)。


2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
danishi
cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?