How to schedule EC2 instances managed by Auto Scaling Groups (start/stop)

Many times, we have a lot of cloud waste because we never shut down our services/EC2 instances. One of the trickiest cases to control is the Auto Scaling Groups.

Now, this tutorial (based on Vicent's one), I'm going to help you automate this task using AWS EventBridge and Lambda functions.

It's important to highlight that you must create two Lambdas:
  1. One for stopping that is going to have a 0 as the environment variables (DESIRED_CAPACITY and MAX_SIZE).
  2. One for starting that is going to have 1+ as the environment variables (DESIRED_CAPACITY and MAX_SIZE).
Now, the steps:

Create new Lambda function and Start Event

  1. Open AWS Lambda in the console and click Create a Lambda function.
  2. Choose Author from Scratch.
  3. Give a name like ScheduleASStart.
  4. For Runtime, select Python 3.9.
  5. Click on Add Trigger.
  6. Choose EventBridge (CloudWatch Events).
  7. Click on Create a new rule.
  8. Enter a Rule name and Rule description.
  9. For Rule type, select Schedule expression.
  10. For Schedule expression, enter a Cron expression to specify at which day(s) and time this event should trigger. For now, only specify the event to start servers (E.g., at the beginning of the weekday). We will configure the second event later in this tutorial. E.g., cron(00 06 ? * MON-FRI *) fires every weekday (Monday to Friday) at 6:00 AM UTC. See this website for a handy Cron calculator.
  11. Click on Add.

Configure function

  1. On the Configure function page, enter a Name and Description for the function.
  2. For Code entry type make sure Edit code inline is selected.
  3. Delete the existing code and paste the following code into the code field:
import os
import boto3

client = boto3.client('autoscaling')

def get_env_variable(var_name):
    msg = "Set the %s environment variable"
    try:
        return os.environ[var_name]
    except KeyError:
        error_msg = msg % var_name

def lambda_handler(event, context):
    auto_scaling_groups = get_env_variable('NAMES').split()

    for group in auto_scaling_groups:
        if servers_need_to_be_started(group):
            action = "Starting"
            min_size = int(get_env_variable('MIN_SIZE'))
            max_size = int(get_env_variable('MAX_SIZE'))
            desired_capacity = int(get_env_variable('DESIRED_CAPACITY'))
        else:
            action = "Stopping"
            min_size = 0
            max_size = 0
            desired_capacity = 0

        print (action + ": " + group)
        response = client.update_auto_scaling_group(
            AutoScalingGroupName=group,
            MinSize=min_size,
            MaxSize=max_size,
            DesiredCapacity=desired_capacity,
        )

        print (response)

def servers_need_to_be_started(group_name):
    min_group_size = get_current_min_group_size(group_name)
    if min_group_size == 0:
        return True
    else:
        return False


def get_current_min_group_size(group_name):
    response = client.describe_auto_scaling_groups(
        AutoScalingGroupNames=[ group_name ],
    )
    return response["AutoScalingGroups"][0]["MinSize"]
  1. For Environment variables add the following:
    • NAMES - Space separated list of the Auto Scaling Groups you want to manage with this function
    • MIN_SIZE - Minimum size of the Auto Scaling Group(s) when EC2 instances are started. e.g., 0
    • MAX_SIZE - Maximum size of the Auto Scaling Group(s) when EC2 instances are started. e.g., 1
    • DESIRED_CAPACITY - Desired capacity of the Auto Scaling Group(s) when EC2 instances are started. e.g., 1
  1. For Role, select Create a custom role. An IAM wizard will open a new tab.
  2. For IAM Role, select Create a new IAM Role.
  3. Enter a Role Name.
  4. Click on View Policy Document and click Edit.
  5. A warning popup will appear. Click Ok.
  6. Add the following statement right after the closing } of "Resource": "arn:aws:logs:*:*:*" }
,
{
    "Effect": "Allow",
    "Action": "autoscaling:*",
    "Resource": "*"
}
  1. Click on Allow.
  2. Back on the Configure function screen, make sure your new Role is selected under Existing role.
  3. Click on Deploy.

Create Stop Event

  1. Create a new function like the first section.
  2. For Environment variables:
    • NAMES - Space separated list of the Auto Scaling Groups you want to manage with this function
    • MIN_SIZE - Minimum size of the Auto Scaling Group(s) when EC2 instances are started. e.g., 0
    • MAX_SIZE - Maximum size of the Auto Scaling Group(s) when EC2 instances are started. e.g., 1
    • DESIRED_CAPACITY - Desired capacity of the Auto Scaling Group(s) when EC2 instances are started. e.g., 0
  3. Click on Add Trigger.
  4. Choose EventBridge (CloudWatch Events).
  5. Click on Create a new rule.
  6. Enter a Rule name and Rule description.
  7. For Rule type, select Schedule expression.
  8. For Schedule expression, enter a Cron expression to specify at which day(s) and time this event should trigger. E.g., cron(00 20 ? * MON-FRI *) fires every weekday (Monday to Friday) at 20:00 PM UTC. See this website for a handy Cron calculator.
  9. Click on Add.

That's it, all done!

You can test the function by hitting the Test button. The first time an Input test event popup will appear.

For the Sample event template select Scheduled event and click Save and test.

Acknowledgement

This tutorial on Nick Todd's blog helped me setting up this tutorial.

Comments