You may have heard you could schedule your instances to be stopped after hours or on weekends to save money but don't know how to. Don't worry, that's exactly what I am going to demonstrate in this article, I will be using AWS lambda to stop the instances at 6 pm and start them in the morning at 6 am.
Summary
Set a cron job to trigger lambda functions that will shutdown/Start the instances based on their selection criteria. I am using tags as my criteria to select instances. You could select instances based on their architecture, instance type, kernel ID, etc.
Why would you implement this solution?
It is a simple, serverless, and AWS native solution, plus it is very cheap(lambda pricing). Additionally, depending on how many instances you stop using this solution, you will be reducing your AWS monthly bill significantly
Solution Setup Steps
1. Instances Selection criteria: Tags
- Search AWS Resource Group --> in the left pane, select tag editor.
- Select a region, and AWS::EC2::Instance resource type --> click on search resources.
- All the instances should prompt up at the bottom --> select the instances you want to apply tags to --> click Manage tags of selected resources
- Click Add tag, enter in
hours
as Tag Key and9-6
as Tag Value --> click review and apply tag changes --> click on apply changes to all selected - Tags have been applied to the instances. Lambda functions will look for instances with these tags
2. IAM Role
A role for lambda functions to execute and stop/start EC2 instances
- Search IAM --> click Roles in the left pane --> click on Create role
- Select
AWS Service
as Trusted entity type,lambda
as Use case --> click Next - Search and select
AWSLambdaBasicExecutionRole
type -AWS managed policy
- Search and select
AmazonEC2FullAccess
type -AWS managed policy
--> click Next - Enter in role name -
EC2Scdeduler
--> click Create role
3. Lambda Functions
I'll create two functions, one of them will stop the instances and the other will start them based on the schedules.
I. Instance Stop Function
- Search AWS Lambda --> select functions --> click Create function
- Enter in function name
stopfunction
--> selectPython 3.9
Runtime andx86_64
Architecture - Expand Change default execution role --> select Use an existing role
- Search and select
EC2Scdeduler role
and click create function - In Code Tab, select lambda_function --> remove everything and enter in the code below --> click Deploy and save
import json
import boto3
client = boto3.client('ec2')
def lambda_handler(event, context):
response = client.describe_instances(
Filters=[
{
'Name': 'tag:hours',
'Values': [
'9-6',
]
},
],
)
print(response)
instances = []
length = len(response['Reservations'])
for i in range(length):
instanceID = response['Reservations'][i]['Instances'][0]['InstanceId']
instances.append(instanceID)
if not instances:
print("No instance found")
else:
response = client.stop_instances(
InstanceIds=instances,
)
ii. Instance Start Function
Almost the same as the stop function, but this starts the instances.
- Search AWS Lambda --> select functions and click Create function
- Enter in function name
startfunction
--> selectPython 3.9
Runtime andx86_64
Architecture - Expand Change default execution role --> select Use an existing role
- search and select
EC2Scdeduler
role and click Create function - In Code Tab, select lambda_function --> remove everything and enter in the code below --> click Deploy and save
import json import boto3 client = boto3.client('ec2') def lambda_handler(event, context): response = client.describe_instances( Filters=[ { 'Name': 'tag:hours', 'Values': [ '9-6', ] }, ], ) print(response) instances = [] length = len(response['Reservations']) for i in range(length): instanceID = response['Reservations'][i]['Instances'][0]['InstanceId'] instances.append(instanceID) if not instances: print("No instance found") else: response = client.start_instances( InstanceIds=instances, )
4. Set schedules for lambda functions
I'll use EventBridge to create schedules that will trigger lambda functions daily.
i. Instance Stop Schedule
- Search Amazon EventBridge --> select Rules under Events in the left pane.
- Click Create rule --> Name
StopInstances
, Event Busdefault
--> Rule type select Schedule --> click Next - Enter in cron expression
0,18,*,*,?,*
for Minutes, Hour, Day of Month, Day of Week and Year. This schedule will run every day at 6pm UTC* - Select Target
Lambda function
as a target,stopfunction
as Function --> click Next - Add tags, enter in
ec2scheduler
as Key --> click Next - Review the rule --> click Create rule
ii. Instance Start Schedule
- Search Amazon EventBridge --> select Rules under Events in the left pane
- Click Create rule --> Name -
StopInstances
--> Event Bus -default
--> Rule type - selectSchedule
--> click Next - Enter in cron expression
0,6,*,*,?,*
for Minutes, Hour, Day of Month, Day of Week and Year.This schedule will run everyday at 6 am UTC* - Select Target
Lambda function
-->stopfunction
as Function --> click *Next - Add tags, enter in
ec2scheduler
as Key --> click Next - Review the rule --> click Create rule
All the resources have been created, instances will be stopped/started based on the schedules set in EventBridge.
Cleanup
If you have created these resources in your lab environment, don't forget to delete them to avoid getting billed.