A major part of your AWS bills comes from EC2 uptime and EBS storage use. In order to save on these costs, it is recommended to stop your instances whenever it is not required. Often times, your Development, Test or UAT environments aren’t used by developers during off-hours. Thus this would be a great time frame to temporarily stop the instances and save up on costs.
In order to do this, we can make use of AWS Lambda, which lets you run your code or without setting up any servers. Since it charges based on the compute time taken up by the code, it is very cost efficient. A task running twice within a 24-hour cycle for typically less than 60 seconds with memory consumption up to 128MB (like the script in this post) typically costs around $0.008 per month.
We will use the official AWS SDK for Python, boto3 to write our script and then run it using Lambda functions.
Pre-requisites
First things first, make sure your IAM user has:
a) Access to AWS Lambda and create functions
b) Full permissions to create Roles on IAM
c) Access to CloudWatch
d) Access to EC2 to tag instances and test the script
Create the Function
Once the permissions are in place, get started with the following steps
-
Create an IAM Role
Create an IAM Role for Lamba to use. You can either create a custom role and give granular permissions. The permissions required are listing, stopping, starting EC2 instances, and listing, creating, modifying CloudWatch logs. Additional dependent permissions may be required so use AWS Policy Simulator to check if you have all the permissions required.
Or you can opt for an AWS Managed Policy. Add AmazonEC2FullAccess and CloudWatchLogsFullAccess permissions to the role.
-
Create two Lambda functions, for starting and stopping the instances using the two scripts below.
- Refer to this guide to get a hang of how to create a simple Lambda function.
- Click on Create a function and then choose Author from scratch.
- Enter a suitable name for the function, change the Runtime to Python.
- Under Role, select Create a custom role. You will be taken to a new page to create the role. Create a policy and then come back to the Lambda page and click Create Function.
- Under Add Triggers, choose CloudWatch Events. Click on the newly created box to configure it. Under Schedule expression,you can add the cron expression you want.
For instancecron<strong>(0 3 ? * MON-FRI *)</strong>
.Note: As a weird caveat, AWS requires the cron expression to contain a ‘?’ in any one of the first four fields. So
cron(0 3 * * MON-FRI *)
will not work butcron(0 3 ? * MON-FRI *)
will. - Then click on the function box and copy paste the above code into the editor window.
- Choose the No VPC option under Network. Keep your Lambda function inside a VPC when the function needs to login into an EC2 instance which is kept in a private subnet and is not publicly accessible. For actions that can be performed over the internet, it is recommended to not put the function inside a VPC. For example, boto’s start and stop API calls are publicly exposed and accessible over the internet which means that Lambda invoke them over the internet but not from within a VPC
- Click on Save and then click on Test for a dry run.
You might want to run a few tests to ensure everything is working as expected. You don’t want your instance to be automatically shut down at 15:00 UTC (or maybe you do)
Comments