AWS SAM で RDS のシャットダウン状態を維持する方法

AWS SAM で RDS のシャットダウン状態を維持する方法

Takahiro Iwasa
(岩佐 孝浩)
Takahiro Iwasa (岩佐 孝浩)
4 min read
CloudWatch Events Lambda RDS

デフォルトでは、 RDS は永続的にシャットダウンできず、7日後に再起動されます。

You can stop a DB instance for up to seven days. If you don’t manually start your DB instance after seven days, your DB instance is automatically started so that it doesn’t fall behind any required maintenance updates.

不要な RDS インスタンスを実行するとコストがかかるため、 AWS SAM で RDS のシャットダウン状態を維持すると有用かもしれません。

前提条件

以下のソフトウェアをインストールしてください。

SAM アプリケーション作成

ディレクトリ構成

/
|-- rds_shutdown/
|   |-- app.py
|   `-- requirements.txt
|-- samconfig.toml
`-- template.yaml

AWS SAM テンプレート

以下の例では Lambda トリガーとして cron 式(24行目)を使用していますが、 EventBridge の RDS イベントがより適切な選択肢です。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Using a CloudWatch Events rule, RdsShutdown keeps an RDS instance shutdown after 1 week.

Parameters:
  RdsDbInstance:
    Type: String

Resources:
  RdsShutdownFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: rds_shutdown/
      Environment:
        Variables:
          DB_INSTANCE: !Ref RdsDbInstance
      Events:
        # CloudWatch Events Rule
        ScheduleEvent:
          Type: Schedule
          Properties:
            Description: An event rule for RdsShutdownFunction
            Enabled: True
            Schedule: 'cron(* */1 * * ? *)'  # every hour
      FunctionName: rds_shutdown
      Handler: app.lambda_handler
      MemorySize: 128
      Role: !GetAtt IamRole.Arn
      Runtime: python3.8
      Timeout: 10

  IamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: policy1
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - rds:DescribeDBInstances
                  - rds:StopDBInstance
                Resource: !Sub arn:aws:rds:*:${AWS::AccountId}:db:${RdsDbInstance}
      RoleName: rds-shutdown

  LogsLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${RdsShutdownFunction}
      RetentionInDays: 30

Python スクリプト

requirements.txt

空のままにしてください。 AWS Lambda ランタイム環境には、デフォルトで boto3 がインストールされているため、 requirements.txt に含める必要はありません。

app.py

次のスクリプトは、 RDS インスタンスのステータスが available の場合にのみ停止します。

import logging
import os

import boto3


# Environment Variables
DB_INSTANCE = os.environ.get('DB_INSTANCE')

logger = logging.getLogger()
logger.setLevel(logging.INFO)

client = boto3.client('rds')


def lambda_handler(event, context):
    if not DB_INSTANCE:
        # Exit when a DB Instance is not specified.
        logger.error('DB_INSTANCE environment variable is not specified.')
        return

    # Get the DB Instance status.
    status = get_db_instance_status(DB_INSTANCE)

    if status == 'available':
        # Stop when the status is available.
        client.stop_db_instance(DBInstanceIdentifier=DB_INSTANCE)
        logger.info(f'DB instance - {DB_INSTANCE} - has been stopped.')


def get_db_instance_status(db_instance: str) -> str:
    # See https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Status.html
    response = client.describe_db_instances(DBInstanceIdentifier=db_instance)
    return response['DBInstances'][0]['DBInstanceStatus']

samconfig.toml

実際の値で <YOUR_S3_BUCKET> および <YOUR_RDS_INSTANCE_NAME> を置き換えてください。

version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "rds-shutdown"
s3_bucket = "<YOUR_S3_BUCKET>"
s3_prefix = "rds-shutdown"
region = "ap-northeast-1"
capabilities = "CAPABILITY_IAM CAPABILITY_NAMED_IAM"
parameter_overrides = "RdsDbInstance=\"<YOUR_RDS_INSTANCE_NAME>\""

ビルドとデプロイ

以下のコマンドでビルドおよびデプロイしてください。

sam build
sam deploy

テスト

RDS インスタンスを停止して、7日間放置し、 Lambda ログを確認してください。以下のレコードが含まれているはずです。

DB instance - database-1 - has been stopped.

以下のコマンドで RDS インスタンスのステータスが stopped であることを確認してください。

$ aws rds describe-db-instances --db-instance-identifier <YOUR_RDS_INSTANCE_NAME> | grep DBInstanceStatus
            "DBInstanceStatus": "stopped",
Takahiro Iwasa
(岩佐 孝浩)

Takahiro Iwasa (岩佐 孝浩)

Software Developer at iret, Inc.
主に AWS を利用したクラウドネイティブアプリケーションの設計および開発をしています。 Japan AWS Top Engineers 2020-2023