こんにちは、インフラエンジニアの川島です。
Auroraの自動停止・自動起動をCloudFormationで作成したので紹介したいと思います。
AWSでコスト削減をしようとすると目に付くのはやはりAuroraだと思います。
Auroraは起動している間、料金が発生し続け、EC2と比べてもとても高いです。
開発環境では常時起動は必要ないため一時停止しようとしても、手動では最大でも7日間しか停止することは出来ず、停止したと思ってたのにいつの間にか起動して料金がすごい事になっていた、なんてこともよくあることと思います。
Amazon Aurora DB クラスターの停止と開始 - Amazon Aurora
本ブログでは下記にて紹介されていた手法をCloudFormationを用いて実装しました。
7 日間を超える期間にわたって Amazon Aurora クラスターを停止する | AWS re:Post
全体像
今回構築するアーキテクチャとしては下記になります。
EventBrdigeが定期起動し、LambdaがAuroraの停止・起動のAPIを叩く事で自動停止・起動を実装しています。

本手法はAuroraに付けられているタグによって停止対象を判別している事が特徴的です。
そのため、停止対象のAuroraが増減した場合にもAuroraのタグを変更するだけでよく、他の手法と比べて手軽に設定することが可能となっています。
設定するパラメータと作成するリソースとしては下記になります。
| 設定するパラメータ | 内容 |
|---|---|
| ProjectName | 任意の値 |
| EnvCode | 任意の値 (dev, stg, …) |
| EventBridgeState | 自動停止・起動の有効、無効 (ENABLED, DISABLED) |
| StartSchedule | 自動起動時刻 (cron式でUTC時刻で設定) |
| StopSchedule | 自動停止時刻 (cron式でUTC時刻で設定) |
| 作成するリソース | リソース名 |
|---|---|
| Lambda用Role | LambdaRole |
| 起動Lambda | AuroraAutoStartLambda |
| 起動Lambda用リソースベースポリシー | PermissionForEventsToInvokeStartLambda |
| 起動EventBridge | AuroraStartEventRule |
| 停止Lambda | AuroraAutoStopLambda |
| 停止Lambda用リソースベースポリシー | PermissionForEventsToInvokeStopLambda |
| 停止EventBridge | AuroraStopEventRule |
テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: "Create AuroraAutoStop template"
Parameters:
ProjectName:
Description: "Project name"
Type: "String"
EnvCode:
Description: "Environment type"
Type: "String"
EventBridgeState:
Description : "EventBridge state"
Type: "String"
AllowedValues:
- "ENABLED"
- "DISABLED"
StartSchedule:
Description: "Start Aurora schedule (cron UTC)"
Type: "String"
StopSchedule:
Description: "Stop Aurora schedule (cron UTC)"
Type: "String"
Resources:
AuroraAutoStartLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import boto3
rds = boto3.client('rds')
def lambda_handler(event, context):
#Start DB clusters
dbs = rds.describe_db_clusters()
for db in dbs['DBClusters']:
#Check if DB cluster stopped. Start it if eligible.
if (db['Status'] == 'stopped'):
doNotStart=1
try:
GetTags=rds.list_tags_for_resource(ResourceName=db['DBClusterArn'])['TagList']
for tags in GetTags:
#if tag "autostart=yes" is set for cluster, start it
if(tags['Key'] == 'autostart' and tags['Value'] == 'yes'):
result = rds.start_db_cluster(DBClusterIdentifier=db['DBClusterIdentifier'])
print ("Starting cluster: {0}.".format(db['DBClusterIdentifier']))
if(doNotStart == 1):
doNotStart=1
except Exception as e:
print ("Cannot start cluster {0}.".format(db['DBClusterIdentifier']))
print(e)
if __name__ == "__main__":
lambda_handler(None, None)
FunctionName: !Sub "${ProjectName}-${EnvCode}-aurora-auto-start-function"
Handler: index.lambda_handler
Runtime: python3.12
Role: !GetAtt LambdaRole.Arn
Timeout: 10
AuroraAutoStopLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import boto3
rds = boto3.client('rds')
def lambda_handler(event, context):
#Stop DB clusters
dbs = rds.describe_db_clusters()
for db in dbs['DBClusters']:
#Check if DB cluster started. Stop it if eligible.
if (db['Status'] == 'available'):
doNotStop=1
try:
GetTags=rds.list_tags_for_resource(ResourceName=db['DBClusterArn'])['TagList']
for tags in GetTags:
#if tag "autostop=yes" is set for cluster, stop it
if(tags['Key'] == 'autostop' and tags['Value'] == 'yes'):
result = rds.stop_db_cluster(DBClusterIdentifier=db['DBClusterIdentifier'])
print ("Stopping cluster: {0}.".format(db['DBClusterIdentifier']))
if(doNotStop == 1):
doNotStop=1
except Exception as e:
print ("Cannot stop cluster {0}.".format(db['DBClusterIdentifier']))
print(e)
if __name__ == "__main__":
lambda_handler(None, None)
FunctionName: !Sub "${ProjectName}-${EnvCode}-aurora-auto-stop-function"
Handler: index.lambda_handler
Runtime: python3.12
Role: !GetAtt LambdaRole.Arn
Timeout: 10
LambdaRole:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: AuroraStartStopPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- rds:StartDBCluster
- rds:StopDBCluster
- rds:ListTagsForResource
- rds:DescribeDBInstances
- rds:StopDBInstance
- rds:DescribeDBClusters
- rds:StartDBInstance
Resource: "*"
PermissionForEventsToInvokeStartLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref AuroraAutoStartLambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt AuroraStartEventRule.Arn
AuroraStartEventRule:
Type: "AWS::Events::Rule"
Properties:
Name: !Sub "${ProjectName}-${EnvCode}-aurora-start-rule"
Description: "Push AuroraStartLambda Batch event rule"
ScheduleExpression: !Ref StartSchedule
State: !Ref EventBridgeState
Targets:
- Arn: !GetAtt AuroraAutoStartLambda.Arn
Id: StartLambdaFunction
PermissionForEventsToInvokeStopLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref AuroraAutoStopLambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt AuroraStopEventRule.Arn
AuroraStopEventRule:
Type: "AWS::Events::Rule"
Properties:
Name: !Sub "${ProjectName}-${EnvCode}-aurora-stop-rule"
Description: "Push AuroraStopLambda Batch event rule"
ScheduleExpression: !Ref StopSchedule
State: !Ref EventBridgeState
Targets:
- Arn: !GetAtt AuroraAutoStopLambda.Arn
Id: StopLambdaFunction
実装方法
対象Auroraにタグを設定
停止対象のAuroraのDBクラスターにタグ autostart:yes, autostop:yes を設定します。
CloudFormationを用いてリソースを作成
上記テンプレートをYAMLファイルとして保存し、コンソール画面からアップロードし、パラメータに適切な値を入力します。
ProjectNameとEnvCodeは任意の値を入力します。
EventBridgeStateは自動停止を有効化する場合はENABLED、無効化する場合はDISABLEDを選択します。
StartScheduleとStopScheduleにはcron式かつUTCで値を入力します。 (例 : cron(15 13 ? * MON *))
cron 式と rate 式を使用して Amazon EventBridge でルールをスケジュールする - Amazon EventBridge
まとめ
今回はタグで停止対象を判別するAuroraの自動停止・起動を紹介いたしました。
停止対象を直接指定していないため、新しいDBを作成した時にもタグを追加するだけで自動停止・起動の対象とする事ができます。
この記事がどなたかのお役に立てば幸いです。