Amazon RDS は一時停止した場合、最大7日間までしか停止できない
しかし停止させたままにしたい状況が発生したため調査を行なった
その際のまとめを備忘録として残しておく
解決案
- Lambda 関数を使用する
- 公式推奨
- EventBridge を使用する
- どちらかというと夜間休日止めるのに最適
実際の手順
Lambda 関数を使用する
-
IAM > ポリシー を選択
-
以下でポリシーを作成
{
"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": "*"
}
]
}
-
IAM > ロール を選択
-
以下でロールを作成
- 信頼できるエンティティタイプを選択: AWS サービス
- またはサービスを選択してユースケースを表示: Lambda
- ポリシー: 手順 2 で作成したポリシー
-
RDS > データベース > «該当の DB インスタンス» を選択
-
以下の様にタグを設定
- autostart: yes
- autostop: yes
-
Lambda > 関数 を選択
-
以下の設定で関数を作成
- オプション: 一から作成
- 関数名: 任意
- ランタイム: Python 3.*
- アーキテクチャ: x86_64
- デフォルトの実行ロールの変更: 手順 4 で作成したロール
-
コード > [コードソース]エディタでサンプルコードを削除して次のコードを入力
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)
-
デプロイする
-
関数の概要 > トリガーを追加 を選択
-
EventBridge (CloudWatch Events) を選択し、[新しいルールを作成] を作成
- ルール名: 任意
- スケジュール式: RDS メンテナンス時間の 30 分前等を指定(cron 式)
- 例. cron(30 21 ? * SUN *)
-
手順 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 を使用する
- 以下の 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:
- "*"
- 以下のパラメータを指定
- 対象のインスタンス(DB 識別子)
- 例. sample-db
- 停止のスケジュール(cron 式)
- 例. cron(0 20 * * ? *)
- タイムゾーン
- 例. japan
-
作成されたリソースを確認
3-1. Amazon EventBridge > スケジュール > «対象のスケジュール»