AWS Cost Optimization: Automating EC2, RDS, and Redis Start/Stop with Lambda
Step-by-Step Guide to Automating EC2, RDS, and Redis Start/Stop During Off-Hours with AWS Lambda
1. Introduction
In cloud environments, managing costs is crucial to maintaining efficiency and profitability. With AWS, services like EC2, RDS, and Redis can run 24/7, incurring charges even when idle. By leveraging AWS Lambda for automation, you can optimize these resources to start and stop during off-hours, reducing unnecessary costs.
2. Why Automate Resource Shutdowns?
EC2, RDS, and Redis instances continue to consume resources even when not in use, leading to higher costs. Automating their shutdown during off-hours helps minimize idle resource consumption, potentially saving up to 50% on monthly cloud expenses. For example, stopping EC2 instances during non-peak times or pausing RDS databases overnight can significantly reduce your AWS bill.
3. Step-by-Step Implementation
Below is a detailed step-by-step guide, along with screenshots, to help you implement the automation process for EC2, RDS, and Redis start/stop during off-hours using AWS Lambda. Follow each stage carefully to ensure a seamless setup.
Step1: In the AWS Management Console, navigate to Lambda Service and create lambda function and edit configuration section to increase Timeout value
and create new policy, attach to created existing lambda function role as shown in below attached screenshots.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"ec2:StartInstances",
"ec2:StopInstances",
"ec2:DescribeInstances",
"rds:DescribeDBInstances",
"rds:StartDBInstance",
"rds:StopDBInstance",
"elasticache:CreateCacheCluster",
"elasticache:DeleteCacheCluster",
"elasticache:DescribeCacheClusters"
],
"Resource": "*"
}
]
}
Note: If you’re using tagged resources, you can narrow the
"Resource": "*"
field to specific ARNs for better security. For example, replace"*"
with the ARNs of your EC2, RDS, or ElastiCache resources.
In the search bar, look for the policy you just created. For example, in my case, it is named lambda-starter-stopper-policy.
Step2: After completing Step 1, click on the newly created Lambda function and enter the script for the EC2, RDS, and Redis instances that you want to automate for starting and stopping. Please use the exact/correct name, instance-id and other required details, for reference check below attached screenshots.
After above configuration is done, please add script to lambda function starter you created earlier like shown below.
import boto3
region = 'ap-south-1' # replace with your actual region
instances = ['i-001g234456ef'] # replace with your actual instance-id
db_instances = ['frm-test'] # replace with your actual db identifier name
ec2 = boto3.client('ec2', region_name=region)
rds = boto3.client('rds', region_name=region)
elasticache = boto3.client('elasticache', region_name=region)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
for db_instance in db_instances:
rds.start_db_instance(
DBInstanceIdentifier = db_instance
)
print('start your instances: ' + str(instances))
response = elasticache.create_replication_group(
ReplicationGroupId='frm-test', # replace with your actual redis cache name
ReplicationGroupDescription='frm-test', # you can keep the name same as cache name
NumCacheClusters=1,
CacheNodeType='cache.t3.micro', # replace with your cache node type
Engine='redis',
EngineVersion='7.1', # replace with your engine-version
CacheSubnetGroupName='subnet-group-redis-project', # replace with your actual subnet group name
SecurityGroupIds=[
'sg-00946312345', # replace with your security-group id used by redis
],
PreferredMaintenanceWindow='sun:01:00-sun:02:00', # replace with your actual details
Port=6379, # replace with your actual redis port
AutoMinorVersionUpgrade=True
)
Step 3: After completing Step 2, follow the same approach to create a Lambda function for stopping resources. Refer to the attached screenshots and script for guidance.
import json
import json
import boto3
def lambda_handler(event, context):
ec2 = boto3.client('ec2')
rds = boto3.client('rds')
elasticache = boto3.client('elasticache')
# Stop EC2 instances
ec2_instances = ['i-001g234456ef'] # replace with your lambda starter mentioned ec2 instance-id
for instance_id in ec2_instances:
ec2.stop_instances(InstanceIds=[instance_id])
# Stop RDS instances
rds_instances = ['frm-test'] # replace with your lambda starter mentioned db identifier name
for instance_id in rds_instances:
rds.stop_db_instance(DBInstanceIdentifier=instance_id)
# Stop ElastiCache/Redis clusters
elasticache_clusters = ['frm-test'] # replace with your lambda starter mentioned redis cache name
for cluster_id in elasticache_clusters:
elasticache.delete_replication_group(ReplicationGroupId=cluster_id)
return {
'statusCode': 200,
'body': json.dumps('Resources stopped successfully')
}
Step4: Create AWS EventBridge scheduler rule for lambda starter/stopper automation. for reference check below mentioned screenshots.
STOPPER REFERENCE:
STARTER REFERENCE:
NOTE: After creating the scheduler, attach it to the respective starter/stopper Lambda functions for automation. Ensure the scheduler is properly linked to the functions. Refer to the attached screenshot for guidance.
Conclusion
By following these steps and creating the AWS EventBridge scheduler rule, you’ve successfully automated the starting and stopping of your resources during off-hours. This approach not only streamlines operations but also significantly optimizes your AWS costs.
Ensure your scheduler rule is correctly set up by referring to the attached screenshots. If you encounter any issues, revisit the steps or consult the official AWS documentation for further assistance.
If this guide was helpful or if you have suggestions for improvement, feel free to share your feedback. Together, we can continue building smarter and more cost-efficient AWS solutions!