Cloud operational cost could add up to a significant amount and could get out of hand very easily if you are not mindful of the services you are using. One major dent in the billing comes from your EC2 instances which are left running 24x7.  

For example, one of the cheapest and most frequently used EC2 instance type is t2.micro which costs $0.0116 per hour, that's a little more than $100 per year. If you use this instance during working hours or day time only then by shutting down those instances when unused could save you more than $50 per year per instance. A typical use case is a developer or a test instance which a developer uses only during working hours.

There are many ways to schedule start and stop AWS EC2 instances automatically, however AWS Instance Scheduler supersedes them all. It allows you to create automatic start and stop schedules for your Amazon EC2 and Amazon RDS instances.

The following diagram shows a high level component architecture of Instance Scheduler. Here, a CloudWatch event triggers a Lambda function which in turn checks the state and schedule of your tagged Instances in Amazon DynamoDB and then starts or stop the instances.

In this article I will show you a step-by-step guide on how to use CloudWatch and AWS Lambda function without the Amazon DynamoDb to trigger start or stop of one EC2 instance as shown in the architecture below.

Step 1: Create IAM Role

  • Login to you AWS account and navigate to IAM
  • Go to Roles and then click on Create Role
  • Select Lambda and click Next:Permissions
  • Create new custom policy by clicking on Create Policy
  • Specify Actions by filtering as following:

List : DescribeInstance, DescribeInstanceStatus and DescribeRegions

Write: StopInstances

  • Select All resources
  • Click on Review Policy, provide a meaningful name and click on Create Policy

Step 2: Create Lambda Function

  • Navigate to Lambda under Compute Services and Create Function
  • Select "Author from Scratch" , give it a meaningful name, select "Python 3.8" in Runtime info.
  • Expand permissions, select use existing role and add the role you have created above
  • Add the following code to the function code section, change the region to your region name and change/add Instance Id  from your EC2 console of those EC2 Instances which you want to shutdown
import boto3
region = 'us-east-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))
  • Scroll down, edit basic settings and change timeout to 30 seconds

Step 3: Create Cloud Watch Trigger

  • In your lambda function designer add trigger
  • Select CloudWatch Events/EventBridge
  • Create new rule, give it a meaningful name and description
  • Select Schedule Expression and add the following cron job expression to trigger it every evening weekday (Monday-Friday) 6PM : cron(0 22 ? * MON-FRI *), the time is in UTC. you can find the details of Schedule Expressions here
  • Save it, the rule will look like this, which you can see in CloudWatch->Rules

Step 4: Repeat Step 2 to create lambda function to Schedule a Start of EC2 instance

Step 5: Test your lambda functions

  • Select one of the functions you have created, drop down "select a test event" and "configure test event". Enter a meaningful name and create. No need to change anything in the json code.
  • Click on Test to execute the function manually. Check your EC2 instance to see if function worked.

You have successfully created a scheduler to Start and Stop EC2 instance.