Stopping EC2 instances on a scheduled basis
Tags: aws, serverless, python, devops
Published: 2020-08-17 19:32:25

The end of August will officially mark a full year of learning AWS and with that comes an end to my free-tier benefits. This had me thinking that maybe it was time to look into discussing AWS budgeting and ways to cut costs. While the majority of my projects that I have completed thus far have been heavily involved with serverless, I thought this would be a great opportunity to look into EC2 cost-saving options as well.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/knayst0dykepnmgt7hta.png)


Those familiar with AWS are well-aware of the benefits of using spot-instances, proper load-balancing and auto-scaling setup and simply choosing the correct type of instance for your usage criteria to begin with. Beyond that, there are still other ways to cut EC2 costs. The first option that came to mind was utilizing CloudWatch events to schedule shut-down of EC2 instances during off-hours. 
For example: Say we have a rather large development business that needs multiple M5 instances up and running during normal business hours of Monday - Friday, 7 a.m. to 5 p.m. We could easily schedule shutdown of these instances at 6 p.m. each night and spin them back up at 6 a.m. the next morning during the week while leaving them shutdown during the weekend. This could potentially lead to quite a large amount of savings over the span of a year. So, what are the steps I would take to go about doing this? Glad you asked!

![Alt Text](https://media.giphy.com/media/12WPxqBJAwOuIM/giphy.gif)

1. First things first, I created a Lambda function from scratch using Python 3.8 as my runtime and added a custom role. This custom role includes the standard access to CloudWatch CreateLogGroups, CreateLogStreams and PutLogEvents but also includes access to EC2 DescribeInstances, DescribeRegions, StartInstances and StopInstances. I named this role, saved and began writing my function code. Here's a screen capture of what this looked like in my policy manager:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b7gv0un35tpggy9kn976.png)

2. Using boto3 I wrote a small amount of code that would get a list of regions, iterate through each region, obtain only the running instances (accomplished this using a filter) and finally stopping the instance while returning "Stopped Instance" and the instance ID. Once this is completed, it's also necessary to increase the function timeout slightly so that there is enough time to run through our code and perform the action of shutting down our instances.

3. Testing the function is the obvious next step. This is to ensure we have proper permissions and our code runs successfully.

4. Now that our Lambda function is working properly we have to setup a trigger that will invoke this function to run. Within CloudWatch events, I created a rule with a cron expression and set a time along with a range of Mon-Fri as well as setting the target as my Lambda function. Once this time is reached, it will trigger the target (my Lambda function) and if all works well will shutdown the running EC2 instances.

I tested this successfully and plan on exploring more ways in the near future to cut costs within the realm of EC2. 

Jerry