Amazon RDS は一時停止した場合、最大7日間までしか停止できない
しかし停止させたままにしたい状況が発生したため調査を行なった
その際のまとめを備忘録として残しておく

解決案

実際の手順

Lambda 関数を使用する

  1. IAM > ポリシー を選択

  2. 以下でポリシーを作成

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "rds:StartDBCluster",
                "rds:StopDBCluster",
                "rds:ListTagsForResource",
                "rds:DescribeDBInstances",
                "rds:StopDBInstance",
                "rds:DescribeDBClusters",
                "rds:StartDBInstance"
            ],
            "Resource": "*"
        }
    ]
}
  1. IAM > ロール を選択

  2. 以下でロールを作成

    • 信頼できるエンティティタイプを選択: AWS サービス
    • またはサービスを選択してユースケースを表示: Lambda
    • ポリシー: 手順 2 で作成したポリシー
  3. RDS > データベース > «該当の DB インスタンス» を選択

  4. 以下の様にタグを設定

    • autostart: yes
    • autostop: yes
  5. Lambda > 関数 を選択

  6. 以下の設定で関数を作成

    • オプション: 一から作成
    • 関数名: 任意
    • ランタイム: Python 3.*
    • アーキテクチャ: x86_64
    • デフォルトの実行ロールの変更: 手順 4 で作成したロール
  7. コード > [コードソース]エディタでサンプルコードを削除して次のコードを入力

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

def lambda_handler(event, context):

    #Start DB Instances
    dbs = rds.describe_db_instances()
    for db in dbs['DBInstances']:
        #Check if DB instance stopped. Start it if eligible.
        if (db['DBInstanceStatus'] == 'stopped'):
            try:
                GetTags=rds.list_tags_for_resource(ResourceName=db['DBInstanceArn'])['TagList']
                for tags in GetTags:
                #if tag "autostart=yes" is set for instance, start it
                    if(tags['Key'] == 'autostart' and tags['Value'] == 'yes'):
                        result = rds.start_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])
                        print ("Starting instance: {0}.".format(db['DBInstanceIdentifier']))
            except Exception as e:
                print ("Cannot start instance {0}.".format(db['DBInstanceIdentifier']))
                print(e)


if __name__ == "__main__":
    lambda_handler(None, None)
  1. デプロイする

  2. 関数の概要 > トリガーを追加 を選択

  3. EventBridge (CloudWatch Events) を選択し、[新しいルールを作成] を作成

    • ルール名: 任意
    • スケジュール式: RDS メンテナンス時間の 30 分前等を指定(cron 式)
      • 例. cron(30 21 ? * SUN *)
  4. 手順 7 〜 12 を行い RDS 自動停止用の関数を作成

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

def lambda_handler(event, context):

    #Stop DB instances
    dbs = rds.describe_db_instances()
    for db in dbs['DBInstances']:
        #Check if DB instance is not already stopped
        if (db['DBInstanceStatus'] == 'available'):
            try:
                GetTags=rds.list_tags_for_resource(ResourceName=db['DBInstanceArn'])['TagList']
                for tags in GetTags:
                #if tag "autostop=yes" is set for instance, stop it
                    if(tags['Key'] == 'autostop' and tags['Value'] == 'yes'):
                        result = rds.stop_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])
                        print ("Stopping instance: {0}.".format(db['DBInstanceIdentifier']))
            except Exception as e:
                print ("Cannot stop instance {0}.".format(db['DBInstanceIdentifier']))
                print(e)

if __name__ == "__main__":
    lambda_handler(None, None)

EventBridge を使用する

  1. 以下の CloudFormation テンプレートを使用して stack を作成
---
AWSTemplateFormatVersion: '2010-09-09'
Description:  EventBridge Scheduler to stop RDS instance

Parameters:
  InstanceId:
    Type: String
  ScheduleStopTime:
    Type: String
    Default: "cron(0 20 * * ? *)"
  ScheduleTimezone:
    Type: String
    Default: Japan

Resources:
  # EventBridgeScheduler???
  ScheduleRDSStop:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: !Sub 'RDS-Stop-${InstanceId}'
      Description: Stop RDS Instance
      ScheduleExpression: !Ref ScheduleStopTime 
      ScheduleExpressionTimezone: !Ref ScheduleTimezone
      FlexibleTimeWindow:
        Mode: "OFF"
      State: ENABLED
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:rds:stopDBInstance
        Input: !Sub |-
          {
            "DbInstanceIdentifier": "${InstanceId}"
          }
        RoleArn:
          Fn::GetAtt:
          - SchedulerRDSStopRole
          - Arn
  # EventBridgeScheduler?????IAM??????     
  SchedulerRDSStopRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - scheduler.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: rdsstop
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - rds:StopDBInstance
                Resource:
                  - "*"
  1. 以下のパラメータを指定
  • 対象のインスタンス(DB 識別子)
    • 例. sample-db
  • 停止のスケジュール(cron 式)
    • 例. cron(0 20 * * ? *)
  • タイムゾーン
    • 例. japan
  1. 作成されたリソースを確認

    3-1. Amazon EventBridge > スケジュール > «対象のスケジュール»