Stop Instances- Automatically Using AWS Lambda
Most of our instances in stage, development and QA may not be in use 24x7. These are mostly used in business hours that are 8–10 hours a day but since the instances are up 24 hours we have to pay for the full day. There may be some cases where you want to actually run instances 24 hours but if its not needed instances can be shut down for off business hours saving lots of money, back of the hand calculation says saving of at least 35%. Include weekends and one can see saving of upto 50%.
Below is solution based on AWS lambda that stops and starts instances based on the time mentioned.
There are two separate lambda functions each for stop and start if instances that’s is triggered by Cloudwatch events. The function searched for EC2 instances for a specific tag and based on that tag start and stops happens.
In this example, we have chosen to include any EC2 instance that has a tag of “Environment” where the value is set to “Development”, but the code and values shown can easily be modified to suit your own requirements.
Follow below steps to start saving on AWS bills.
Creating an IAM policy for the Lambda function stopping instances at off-hours:
- Navigate to IAM in your management console.
- Select “Policies” in the sidebar.
- Click “Create Policy”.
- Select “Create Your Own Policy”.
- Enter an appropriate policy name and description.
- Paste the following JSON into the policy document:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StopInstances"
],
"Resource": [
"*"
]
}
]
}
7. Click “Create Policy”.
Creating the IAM role for the Lambda function stopping instances at off-hours:
1. Select “Roles” in the sidebar.
2. Click “Create New Role”.
3. Enter an appropriate role name and click “Next Step”.
4. Select “AWS Lambda” within the AWS Service Roles.
5. Change the filter to “Customer Managed”, check the box of
the policy you just created, and click “Next Step”.
6. Click “Create Role”.
Creating the Lambda function stopping instances at off-hours:
1. Navigate to Lambda in your management console.
2. Click “Create a Lambda function”.
3. Select the “Blank Function” blueprint.
4. Under “Configure triggers”, click the grey box and select “CloudWatch Events — Schedule”.
5. Enter an appropriate rule name and description.
6. I you want the instances to be stopped at 7:00PM after the workday, cron expression for this is 0 7 ? * MON-FRI *. You’ll need to change this based on when you want
the instances to stop and what time zone you’re in.
7. Check the box to “Enable trigger” and click “Next”.
8. Enter an appropriate function name and description. Select Node.js for the runtime.
Under “Lambda function code”, select “Edit code inline” for the Code entry type and paste the following code in the box:
var AWS = require("aws-sdk");
exports.handler = (event, context, callback) => {
var ec2 = new AWS.EC2();
var describeParams = { Filters: [
{
Name:"tag:Environment",
Values: [
"Development"
]
},
{
Name:"instance-state-name",
Values: [
"running"
]
}
]};
var instances = [];
ec2.describeInstances(describeParams, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
for (var i = 0; i < data.Reservations.length; i++) {
for (var j = 0; j < data.Reservations[i].Instances.length; j++) {
var instanceId = data.Reservations[i].Instances[j].InstanceId;
if (instanceId != undefined && instanceId != null && instanceId != "") {
instances.push(instanceId);
}
}
}
if (instances.length > 0){
var stopParams = { InstanceIds: instances };
ec2.stopInstances(stopParams, function(err,data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
});
}
}
});
};
1. Leave Handler as “index.handler”.
2. Choose to use an existing role and select the IAM role you created earlier for stopping instances.
3. You may want to select a higher value for the Timeout depending on how many instances will be involved in this process.
4. Leave the other default values and click “Next”.
5. Click “Create function”.
Creating the IAM policy for the Lambda function starting instances at on-hours:
1. Navigate to IAM in your management console.
2. Select “Policies” in the sidebar.
3. Click “Create Policy”.
4. Select “Create Your Own Policy”.
5. Enter an appropriate policy name and description.
Paste the following JSON into the policy document:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:StartInstances"
],
"Resource": [
"*"
]
}
]
}
6. Click “Create Policy”.
Creating the IAM role for the Lambda function starting instances at on-hours:
1. Select “Roles” in the sidebar.
2. Click “Create New Role”.
3. Enter an appropriate role name and click “Next Step”.
4. Select “AWS Lambda” within the AWS Service Roles.
5. Change the filter to “Customer Managed”, check the box of the policy you just created, and click “Next Step”.
6. Click “Create Role”.
Creating the Lambda function starting instances at on-hours:
1. Navigate to Lambda in your management console.
2. Click “Create a Lambda function”.
3. Select the “Blank Function” blueprint.
4. Under “Configure triggers”, click the grey box and select “CloudWatch Events — Schedule”.
5. Enter an appropriate rule name and description.
6. I want the instances to be started at 7:00AM before the workday, cron expression for this is 0 7 ? * MON-FRI *. You’ll need to change this based on when you want the instances to start and what time zone you’re in.
7. Check the box to “Enable trigger” and click “Next”.
8. Enter an appropriate function name and description. Select Node.js for the runtime. Under “Lambda function code”, select “Edit code inline” for the Code entry type and paste the following code in the box:
var AWS = require("aws-sdk");
exports.handler = (event, context, callback) => {
var ec2 = new AWS.EC2();
var describeParams = { Filters: [
{
Name:"tag:Environment",
Values: [
"Development"
]
},
{
Name:"instance-state-name",
Values: [
"stopped"
]
}
]};
var instances = [];
ec2.describeInstances(describeParams, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
for (var i = 0; i < data.Reservations.length; i++) {
for (var j = 0; j < data.Reservations[i].Instances.length; j++) {
var instanceId = data.Reservations[i].Instances[j].InstanceId;
if (instanceId != undefined && instanceId != null && instanceId != "") {
instances.push(instanceId);
}
}
}
if (instances.length > 0){
var stopParams = { InstanceIds: instances };
ec2.startInstances(stopParams, function(err,data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
});
}
}
});
};
- Leave Handler as “index.handler”.
- Choose to use an existing role and select the IAM role you created earlier for starting instances.
- You may want to select a higher value for the Timeout depending on how many instances will be involved in this process.
- Leave the other default values and click “Next”.
- Click “Create function”.
Feel free to modify this solution to achieve your specific needs. Hopefully, this will allow you to save some money on your AWS bill every month.