Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / AWS

Start/Stop RDS Instances on Schedule

5.00/5 (7 votes)
5 Jun 2017CPOL3 min read 61.1K   761  
How to start/stop RDS instances on schedule with aws-sdk, nodeJs Lambda function and CloudWatch

Introduction

As you might know, AWS recently added an ability to start and stop RDS instances, which can be really helpful for anyone who wants to save some costs on AWS bill. Let's use AWS Lambda function with CloudWatch events to stop RDS instances used by testing environment at night and on weekends.

Using the Code

First, let's create policy, which is in AWS IAM console. Go to Services -> Policies -> Create Policy -> Create Your Own Policy.

Let's call it RDSManagement. Put the code given below to the 'Policy Document' field:

JavaScript
{
    "Version": "2012-10-17",
    "Statement": [        
        {
            "Action": [
                "rds:StopDBInstance",
                "rds:StartDBInstance"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

Press 'Create policy', Create Your Own Policy put name, description and JSON to the appropriate fields and press Save. Eventually, you have to get something like on the screenshot below:

The second step is to create a role which will be associated with lambda function and allow it to manage RDS instances.

Navigate to Services -> Roles -> Create New Role. Select 'AWS Lambda' in 'AWS Service Role' section. Search for the policy we created previously, select it, and press 'Next'. Put LambdaRDSManagement as a Role Name, set some description and press 'Create Role'.

Now we are ready to go and create lambda function which will manage our instances. Navigate to Services -> Lambda -> Create a Lambda function -> Blank function. Let's call it 'ManageRDSInstances', select latest Node js 6.x as a runtime. Ignore lambda function code for now, and select 'Choose an existing role' in 'Role' field. You have to be able to find the previously created role in 'Existing role' field. Press 'Next' -> 'Create function'.

Good, a puppet for the function is created and ready to go. You can check out a repo on github, clone it, run 'npm install', archive the whole folder to a '.ZIP' file. (Or just download it - rds-lambda-stop-start.zip). We are using original aws-sdk for node js provided by Amazon.

It contains mainly three files:

  1. index.js - which is an actual lambda function which will handle your CloudWatch event:
    JavaScript
    var startInstance = require('./start');
    var stopInstance = require('stop');
    
    exports.handler = (event, context, callback) => {
        event.instances.forEach((instance) => {
            switch (event.action) {
                case 'stop':
                    console.log(`Stopping instance '${instance}'...`);
                    stopInstance(instance);
                    break;
                case 'start':
                    console.log(`Starting instance '${instance}'...`);
                    startInstance(instance);
                    break;
                default:
                    throw `Invalid action ${event.action}`;
            }
        })
        callback(null, 'Done!');
    };
  2. stop.js, which stops running instance and create RDS snapshot in format "{instanceId}-{day}-{month}-{year}-{ticks}":
    JavaScript
    var AWS = require('aws-sdk');
    
    module.exports = (instanceId) => {
      var rds = new AWS.RDS();
      var today = new Date();
      var params = {
        DBInstanceIdentifier: instanceId,
        DBSnapshotIdentifier: `${instanceId}-${today.getDate()}-
                               ${today.getMonth() + 1}-${today.getFullYear()}-
                               ${today.getTime()}`
      };
      rds.stopDBInstance(params, function (err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data);           // successful response
      });
    };
  3. start.js which starts stopped instance.
    JavaScript
    var AWS = require('aws-sdk');
    
    module.exports = (instanceId) => {
      var rds = new AWS.RDS();
      var params = {
        DBInstanceIdentifier: instanceId
      };
      rds.startDBInstance(params, function (err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data);           // successful response
      });
    };

Now let's upload our archive to newly created lambda function. Services -> Lambda -> ManageRDSInstances, and change Code entry type to 'Upload a .ZIP file'. Press 'Upload', select your zip file and press 'Save'. Now we need to configure test event: Actions -> Configure test event.

JavaScript
{  
   "instances":[  
      "some-test-instance-1",
      "some-test-instance-2"
   ],
   "action":"stop"
}

Where some-test-instance-1 and some-test-instance-2 are your testing RDS instances. After pressing 'Save and Test', you will see that your RDS instances changed state to 'Stopping' and soon to 'Stopped'. Presto!

After they are stopped, you can run the same test with action 'start', which will run change state of instances to running.

The last thing is to set up CloudWatch rules to trigger these function on schedule. Services -> CloudWatch -> Rules -> Create Rule. Select Schedule instead of default Event Pattern. Now you need to set up cron time, you can read more about it here. Keep in mind that time must be set in GMT timezone. For instance, to correctly start instances every morning Monday to Friday at 8 am in GMT+12 timezone cron time will look like this: '0 20 ? * SUN-THU *'.

After you set cron time for waking up your instances, select Lambda function as a Target and pick your newly create lambda function. Then in Configure Input section, put your JSON to Constant(JSON text) field:

JavaScript
{ "instances": ["some-test-instance-1",
"some-test-instance-2"], "action":"start" }

Configure Details -> Update rule. Done!

Now your instances will be woken every morning from Monday to Friday. Create a similar rule with correct cron time for stopping them, do not forget to change action from start to stop in the json:

JavaScript
{ "instances": ["some-test-instance-1",
"some-test-instance-2"], "action":"stop" }

Points of Interest

Starting/stopping RDS instances was a feature which was expected for a long while, and finally, guys from Amazon provided this functionality. Hopefully, this will reduce your AWS bill as well. :)

History

  • 2nd June, 2017 - Article created
  • 3rd June, 2017 - Fixed small mistakes, added images

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)