Using AWS Instance Scheduler
Automate the start/stop of your EC2 and RDS instances and save money
For starters in AWS, it can be a painful experience to set up environments and try not to consume all the free-tier capacity or the budget you have provisioned for your tests, or any new small app; and as consequence of forgetting to shutdown or deleting things, receiving the infamous bill and the subsequent panic.
AWS is a behemoth and many have come to believe, that because of this, that it wants you to consume its services, through periodic and tiny amount expenses, disregarding any economic impact that may have on their potential or actual customers; every penny counts some say.
But no, the most interested party in the issue of keeping your costs at bay its AWS itself. For that reason, they provide a handy tool to control the costs of two of the headaches that usually accompany us when we’re starting spinning up things, EC2s and RDSs, we forgot about those too often and commonly, they’re the costliest services. This tool is the AWS Instance Scheduler (https://aws.amazon.com/fr/solutions/instance-scheduler/)
o setup this we’re going to need:
- An active AWS account
- AWS-CLI installed and configured
- Willing to risk a buck or two, (according to AWS it’s like $5/month https://docs.aws.amazon.com/solutions/latest/instance-scheduler/overview.html)
The Architecture
For this solution we’re going full server-less, this solution uses AWS Lambda as the engine that will do the heavy lifting, CloudWatch for event scheduling and monitoring, and DynamoDB for storing the configuration of the scheduler.
The solution works by checking a custom tag that will be applied to the EC2 and RDS resources that will be linked to the schedule you want to apply. This schedules are stored in a DynamoDB table; and yes you can have many schedules for different resources.
More clearly:
- You define during the initial instance scheduler configuration a tag key named “Schedule”, and then you create a schedule named “weekdays-office-hours”. Also you define the AWS Regions on which the scheduler will be checking resources.
- The key name and the schedule name are stored on the DynamoDB table
- You apply this Key:value pair to the resources (EC2 and RDS instances) you want to monitor for start/stop
- A CloudWatch event that runs regularly runs the Lambda Function that will check the compliance with the schedule defined for each resource, and apply the necessary actions according to that schedule, whether to start or stop the resources
- The scheduler also, will be able to apply user-defined tags when any action is taken over the resources
We launch all services through a CloudFormation template kindly provided by AWS. On this template we can configure the behavior we want from the scheduler, and also we can make changes to the parameters and schedules through ChangeSets (changes made to a previously created CloudFormation Stack, if you’re not familiar with the term). Finally we’re going to see how to use the scheduler-cli, through which we can make configuration changes among other things.
The Configuration
We’re doing all the configuration through the AWS Console just for graphic illustration, my preferred method of doing this is through the AWS CLI. This is an overview of what’s next:
- Deploy the cloudformation template
- Define instance scheduler parameters
- Configure Schedules
- Tag Instances
- Check metrics and use scheduler-cli
First, take a look at the diagram of what we’re going to deploy:
We have two DynamoDB tables, one for configuration and one for storing instances state. Also, we have a policy to allow certain services to be used by the scheduler, as well as a role for the lambda function to assume; and of course, the lambda function that will do the heavy lifting and the CloudWatch configuration for triggering it.
First the usual, type a name, but must importantly, choose a Tag name. This tag name will need to be present at the instances we want to control through our scheduler.
Then the services we’re going to watch over…ahh! and if the scheduler should create an RDS snapshot before shutting down.
Aurora clusters, yes we can! but in this post: no we won't. Yes we will enable the schedule…and we must define which regions are going to be probed by the instance scheduler.
We have to indicate the frequency of our probes, also the memory footprint of our lambda function; because I’m still on the free tier, I chose 128Mb, in that manner my runtime will be free of charge (for the moment 😂). Then, there are some CloudWatch configuration parameters, such as, if we enable detailed information (red banner! this cost US$1 per schedule). Finally we set a couple of tags the scheduler will set on the instances that it starts/stops.
Then we should tag our stack, because YOU SHOULD TAG EVERYTHING in AWS, that’s not optional, is good for your mental (and financial) health.
Then we check everything is OK and ACK that CloudFormation should allow certain capabilities for the resources to be created.
Then after 5–10 minutes we check everything is created, in our resources and outputs tabs.
Outputs…check.
We’re now ready to continue to configure the periods, schedules and see if everything works well.
Configuring Periods and Schedules
Now we have to configure the periods on which we’ll start and stop instances, these periods are associated with the schedules, that finally will be tagged to the instances we want.
For this configuration we are going to use the scheduler-cli, this because is the most straightforward way to do it, without tinkering with DynamoDB table (can mess things up), or creating a CloudFormation custom resource, that could be complex if you’re just starting with AWS.
First we need to install the scheduler-cli, this we do by downloading a zip file from here: https://s3.amazonaws.com/solutions-reference/aws-instance-scheduler/latest/scheduler-cli.zip, then we unzip it and run:
python setup.py install
Of course you’ll have to install Python3 before that. You can play a little with the command to see what options are:
scheduler-cli --help
Trying not to make this post any longer, than it already is; we are going to bypass the lots of options that the tool offers.
Configuring the period
We could configure a lot of periods, saying for instance, start all my instances on Mondays at 9am, and then on Friday night stop them all. For sake of time (mine), and because as the time of this post is Sunday, I’ll implement a period that starts all my RDS and EC2 at 3pm UTC-5 (Bogota time, I’m from Colombia! 🇨🇴) and that stops them at 6pm; but I’ll put an example command of a weekday start-weekend stop after that.
First, we specify the start period, don’t forget your CloudFormation Stack name!:
scheduler-cli create-period --stack MyInstanceSchedulerStack --name sun-start-3pm
--weekdays sun --begintime 15:00 --endtime 17:59 --profile your-profile
And finally, the schedule:
scheduler-cli create-schedule --stack MyInstanceSchedulerStack --name sun-3pm-6pm --periods sun-start-3pm --timezone America/Bogota --profile your-profile --region us-west-2
The name of this schedule is what we’ll need to put in our EC2 or RDS instances.
After we add this tag and the schedule name as value, we just wait and see that our instances are started at 3pm:
And we can see the launch time in the EC2 console:
And after a couple of hours we see that our instances are stopped after 6pm:
So, what if you want the mon-fri typical schedule? Here it is!
scheduler-cli create-period --stack <stackname> --name mon-start-8am
--weekdays mon --begintime 8:00 --endtime 23:59scheduler-cli create-period --stack <stackname> --name tue-thu-full- day --weekdays tue-thuscheduler-cli create-period --stack <stackname> --name fri-stop-6pm - -weekdays fri --begintime 0:00 --endtime 18:00scheduler-cli create-schedule --stack <stackname> --name mon-9am-fri- 5pm --periods mon-start-8am,tue-thu-full-day,fri-stop-6pm –timezone America/New_York
The bottom line
Instance Scheduler may seem a little overkill by the amount of configuration and resources needed to make it work, but it certainly will help to control your costs in AWS; and I think it worths the effort (and money), just to prevent a very expensive bill to arrive.
And of course, it’s just limited to two AWS services, maybe in the future will be more, who knows; but you could achieve a lot more of things with AWS Config (https://aws.amazon.com/config/), CloudCustodian (http://cloudcustodian.io/) and Terraform (https://www.terraform.io).
All your comments are welcome. If you like to connect with me here is my LinkedIn profile: LinkedIn