Keeping RDS Shutdown Status with AWS SAM
By default, RDS cannot be shutdown permanently, restarting after seven days.
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.
Running unnecessary RDS instances would incur costs, so AWS SAM might be useful for keeping RDS shutdown status.
Prerequisites
Install the following on you computer.
- AWS SAM
- Python 3.x
Creating SAM Application
Directory Structure
/
|-- rds_shutdown/
| |-- app.py
| `-- requirements.txt
|-- samconfig.toml
`-- template.yaml
AWS SAM Template
The example below uses cron expression as Lambda trigger (line 24), although RDS events with EventBridge should be a more suitable choice.
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 Script
requirements.txt
Leave it empty.
The AWS Lambda runtime environment has boto3
installed by default, so there is no need to include it in your requirements.txt
.
app.py
The script stops the RDS instance only when its status is 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
Replace <YOUR_S3_BUCKET>
and <YOUR_RDS_INSTANCE_NAME>
with the actual value.
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>\""
Build and Deploy
Build and deploy with the following command.
sam build
sam deploy
Testing
Stop your RDS instance, leave it for 7 days, and check the Lambda logs. It should contain the following records.
DB instance - database-1 - has been stopped.
Confirm the RDS instance status is stopped
with the following command.
$ aws rds describe-db-instances --db-instance-identifier <YOUR_RDS_INSTANCE_NAME> | grep DBInstanceStatus
"DBInstanceStatus": "stopped",
Conclusion
Please keep in mind that RDS cannot be shutdown permanently.
I hope you will find this post useful.