AWS SAM を使用した RDS 停止ステータスの効率的な管理

AWS SAM を使用した RDS 停止ステータスの効率的な管理

岩佐 孝浩
岩佐 孝浩
5 min read
CloudWatch Events Lambda RDS

はじめに

デフォルトでは、Amazon 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.

この挙動により、使用されていないインスタンスでも 不要なコスト が発生する可能性があります。本記事では、AWS SAM を使用して RDS インスタンスの停止を自動化し、その停止状態を維持する方法を解説します。

前提条件

以下のツールがシステムにインストールされていることを確認してください。

AWS SAM アプリケーションの作成

ディレクトリ構造

以下は SAM アプリケーションのディレクトリ構造です。

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

AWS SAM テンプレート

このテンプレートでは、CloudWatch Events ルールを使用して cron (23 行目) でトリガーされる Lambda 関数を定義します。代わりに、より詳細な制御を行うため RDS イベントと EventBridge を検討することもできます。

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:
        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

追加の依存関係は不要です。boto3 は AWS Lambda ランタイムにすでに含まれています。

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.

以下の AWS CLI コマンドでインスタンスのステータスを確認してください。

aws rds describe-db-instances --db-instance-identifier <YOUR_RDS_INSTANCE_NAME> | grep DBInstanceStatus

次のような出力が表示されます。

"DBInstanceStatus": "stopped",

まとめ

AWS SAM と Lambda 関数を使用して RDS インスタンスの停止を自動化することで、コスト削減とリソース管理を効率化できます。ただし、RDS インスタンスを無期限に停止状態に維持することはできない点に注意してください。

Happy Coding! 🚀

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023