Ends in
00
days
00
hrs
00
mins
00
secs
ENROLL NOW

$3 OFF all reviewers plus chance to win freebies extended up to this week

Automatically stop non-production RDS databases with AWS Lambda and Amazon EventBridge

Every AWS service offering comes with a pay-as-go pricing model, empowering businesses, small or large, to be flexible at experimenting and making changes as they build their products to market. This pricing model is similar to riding an Uber, where you only pay for the distance covered, or to electric bills where you’re charged based on actual energy consumption. Of course, the more devices you have running, the higher your monthly bill will be. Cloud computing, like any other utility, should be treated the same way.

Just as we are told to unplug appliances when not in use, removing/stopping unused resources is a common strategy for reducing expenditures in AWS. While this may not apply to critical resources that must be online 24/7, shutting down non-production resources and restarting them only during work hours is a straightforward yet effective way of avoiding unnecessary charges.

In this article, we’ll look at implementing an automated solution for stopping/starting non-production RDS instances on schedule using the combination of Amazon EventBridge and AWS Lambda. Stopping RDS instances can be done manually through the RDS management console. With that said, you could assign someone in your team to turn off all RDS instances you have in your test environment before clocking out and have them restart once access is needed the following day. This process might be tolerable for a handful of databases; however, with several test databases to manage, clicking each of them through the console can get tedious and become a time-consuming task. It won’t also help if you’re someone like me who tends to forget things once in a while, hence, automation is the way to go.

Before we get into the implementation details, let’s have a quick overview of the general billing concept in Amazon RDS. RDS instances are billed for DB instance hours, provisioned storage, backup storage, I/O requests, provisioned IOPS, and data transfer. Out of these 6, provisioned storage and DB instance hours (compute time) account for most of RDS costs.

Note that we can only control the number of instance hours accrued over time. You’d have to pay for storage regardless of whether your DB instance is stopped or running. The only way to truly eliminate storage costs is to terminate your database instances.

Below is the overview of the solution that we’ll be building. In this post, we’ll assume that all test RDS instances are located in the N. Virginia region. Having a common region for test resources makes management much easier. In addition, we consider the standard working hours (9AM-5PM) during which the instances must remain active.

The solution comprises 5 components, which are briefly described as follows:

  1. stop-rds Lambda function – contains the logic for stopping all RDS instances

  2. start-rds Lambda function – contains the logic for starting all RDS instances

  3. stop-rds EventBridge Scheduled rule – invokes the stop-rds Lambda function

  4. Tutorials dojo strip
  5. start-rds EventBridge Scheduled rule – invokes the start-rds Lambda function

  6. rds-stop-start execution role –  Execution roles are used by Lambda functions to interact with other AWS services. In our case, we must grant AWS Lambda the necessary permissions to allow it to stop and start database instances on our behalf.

STEPS:

  1. Create an IAM policy for the rds-stop-start execution role. On the IAM Console, click Policies then Create Policy.

2. Attach the following IAM permissions in the JSON editor. We’ll skip adding a tag. Click Next:Tags > Next:Review to proceed to the final step.

3. Enter rds-stop-start-policy in the name field. Click Create policy.

4. Next, let’s create the rds-stop-start execution role. On the IAM Console, click Roles then Create role.

5. Select AWS Lambda as the trusted entity and click Next.

6. Filter rds-stop-start-policy and select it. Click Next.

7. Enter rds-stop-start as the role’s name. Scroll down to the bottom of the page and click Create role.

Now that the execution role has been created, head over to the AWS Lambda console and create a Lambda function.

8. Create the Lambda function that will stop the RDS instances. Name the function stop-rds. Select Python as the runtime. If you wish to write in other supported languages, just google “aws sdk <language> docs“ to get the API reference. Under Execution role, select Use an existing role and search for the role that we created earlier. Finally, click Create function.

9. Replace the hello world sample code with the following:

import boto3
import botocore

rds = boto3.client('rds', region_name='us-east-1')


def lambda_handler(event, context):
        # get all mysql db instances
    rds_mysql = rds.describe_db_instances(Filters=[
        {
            'Name': 'engine',
            'Values': ['mysql']
            
        }])
    for db in rds_mysql['DBInstances']:
        # stop all rds instances
        
        try:
            rds.stop_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])
        except botocore.exceptions.ClientError as err:
            print(err)
    # get all aurora db clusters
    rds_aurora = rds.describe_db_clusters()
        #stop all aurora cluster
    for aurora_cluster in rds_aurora['DBClusters']:
        try:
            rds.stop_db_cluster(DBClusterIdentifier=aurora_cluster['DBClusterIdentifier'])
        except botocore.exceptions.ClientError as err:
            print(err)

You could create a static list of all non-production RDS instances and loop through it, however, this method requires you to update the list every time an instance is added or terminated. To avoid this, we’ll simply use the describe_db_instances API. This function returns various details about all existing RDS instances in a region. It’s also important to note that the stop_db_instance API is incapable of turning off instances that are part of an Aurora cluster, hence, I applied the Filter attribute to exclude them and only grab DB instances that use MySQL. This makes sense for our setup since we’re not using any engine other than MySQL. To stop an Aurora cluster, use describe_db_clusters to get a list of clusters and then call the stop_db_cluster API.

10. Create the start-rds function by using steps 7-9 as a guide. This time, name the function start-rds and copy-paste the following code:

import boto3
import botocore

rds = boto3.client('rds', region_name='us-east-1')


def lambda_handler(event, context):
        # get all mysql db instances
    rds_mysql = rds.describe_db_instances(Filters=[
        {
            'Name': 'engine',
            'Values': ['mysql']
            
        }])
    for db in rds_mysql['DBInstances']:
        # start all rds instances
        
        try:
            rds.start_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])
        except botocore.exceptions.ClientError as err:
            print(err)
    # get all aurora db clusters
    rds_aurora = rds.describe_db_clusters()
        #start all aurora cluster
    for aurora_cluster in rds_aurora['DBClusters']:
        try:
            rds.start_db_cluster(DBClusterIdentifier=aurora_cluster['DBClusterIdentifier'])
        except botocore.exceptions.ClientError as err:
            print(err)

Our solution is almost complete. The only thing missing now is to run the Lambda functions on schedule. To do this, we’ll create two Amazon EventBridge rules that will invoke the stop-rds and start-rds functions.

11. On the Amazon EventBridge console, click Create rule.

12. Under Rule detail, enter stop-rds as the rule name and select the Schedule rule type. Click Next.

AWS Exam Readiness Courses

13. Write the desired CRON expression. The sample below triggers the stop-rds Lambda function every 5 PM GMT +8 from Monday to Friday. Click Next.

14. Specify the stop-rds Lambda function as a target. Click Next > Next > Create Rule

15. Create the event rule that will trigger the start-rds function. Use steps 11-14 as a guide. This time, replace the CRON expression with 0 1 ? * MON-FRI * to restart the RDS instances at 9 AM every Monday to Friday.

Tutorials Dojo portal

Win Exciting Freebies!

FREE AWS Exam Readiness Digital Courses

Enroll Now – Our Azure Certification Exam Reviewers

azure reviewers tutorials dojo

Enroll Now – Our Google Cloud Certification Exam Reviewers

Tutorials Dojo Exam Study Guide eBooks

tutorials dojo study guide eBook

Subscribe to our YouTube Channel

Tutorials Dojo YouTube Channel

FREE Intro to Cloud Computing for Beginners

FREE AWS, Azure, GCP Practice Test Samplers

Browse Other Courses

Generic Category (English)300x250

Recent Posts

Written by: Carlo Acebedo

Carlo is a cloud engineer and a content creator at Tutorials Dojo. He's also a member of the AWS Community builder and holds 5 AWS Certifications. Carlo specializes in building and automating solutions in the Amazon Web Services Cloud.

AWS, Azure, and GCP Certifications are consistently among the top-paying IT certifications in the world, considering that most companies have now shifted to the cloud. Earn over $150,000 per year with an AWS, Azure, or GCP certification!

Follow us on LinkedIn, YouTube, Facebook, or join our Slack study group. More importantly, answer as many practice exams as you can to help increase your chances of passing your certification exams on your first try!

View Our AWS, Azure, and GCP Exam Reviewers Check out our FREE courses

Our Community

~98%
passing rate
Around 95-98% of our students pass the AWS Certification exams after training with our courses.
200k+
students
Over 200k enrollees choose Tutorials Dojo in preparing for their AWS Certification exams.
~4.8
ratings
Our courses are highly rated by our enrollees from all over the world.

What our students say about us?