Start and Stop EC2 Instances with Event Bridge Scheduler Using Universal Targets

Andres CubillosAndres Cubillos
4 min read

Managing EC2 instances efficiently is a common challenge for AWS users. Whether it's optimizing costs or ensuring resources are available when needed, automating these tasks can save time and effort. This is where EventBridge Scheduler comes inโ€”a fully managed, serverless service by AWS that allows you to create and run tasks with ease.

Recently, I faced a real-world scenario: I needed to automatically start EC2 instances every Saturday at a specific time and shut them down a few hours later. While AWS offers various solutions to achieve this, many involve additional steps, like writing custom code for a Lambda function. While such approaches work well for complex workflows, they can be overkill for simple tasks like starting and stopping instances.

Thatโ€™s when I discovered the power of EventBridge Scheduler and its Universal Targets feature. This feature lets you directly invoke APIs from various AWS services, including EC2, without the need for intermediate code. Using this approach, I seamlessly automated the startInstances and stopInstances actions.

letโ€™s do it step by step :

  1. Go to the AWS console and search for EventBridge.

  2. Create an EventBridge scheduler, and provide a name and description.

  1. Choose the schedule pattern you want to use: a One-time schedule to run the task once at a specific time, or a Recurring schedule that allows for a Cron-based expression or a rate-based expression.

  1. Now you can choose between Templated Targets, which offer a set of common API operations across core AWS services like Amazon SQS, Lambda, and Step Functions. In this tutorial, we'll use Universal Targets (All APIs), which provide a customizable set of parameters allowing you to invoke a wider range of API operations for many AWS services. For example, you can use a Universal Target parameter (UTP) to create a new Amazon SQS queue.

  • Once you are in this option, you can use a wide range of API operations for many AWS managed services. For example, in this tutorial, we will focus on EC2.

  • Now, EC2 instance APIs are filtered in the results, so you need to choose the operation you want to invoke, such as stopping an EC2 instance. The selected option requires a payload that you must fill with the necessary information to complete the task. For more details, you can refer to the API Reference document for the operation you are implementing, for example, https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html

  1. Final Configurations: Here are some options to set up how this scheduled task will work:

    • Enable schedule: You can choose to create this schedule as off and turn it on later, or have it turned on from the start.

    • Action after schedule completion: If you choose DELETE, EventBridge Scheduler will automatically delete the schedule after it completes its last invocation and no future target invocations are planned.

  • DLQ: You can specify a queue for retrying failed invocations.

  • Encryption: By default, metadata is encrypted with the AWS key, but you can set up your encryption configuration.

  • Permissions: You need to create an IAM role with the permissions needed to perform the task. In this example, the role should have permissions to StopInstances and StartInstances.

Deploying Eventbridge scheduler task using AWS CDK

All the steps provided previously can be achieved through code using AWS CDK, lets take a look at the code.

//๐Ÿ‘‡ Create an IAM role that EventBridge Scheduler can assume to call EC2 API operations.
 const schedulerRole = new Role(this, "SchedulerRole", {
      assumedBy: new ServicePrincipal("scheduler.amazonaws.com"),
      managedPolicies: [
        ManagedPolicy.fromAwsManagedPolicyName("AmazonEC2FullAccess"),
      ],
    });

// ๐Ÿ‘‡ Schedule to start an EC2 instance
new CfnSchedule(this, `${ParameterNames.PROJECT_NAME}-EC2-scheduler-start`, {
      name: `${ParameterNames.PROJECT_NAME}-Start`,
      flexibleTimeWindow: {
        mode: "OFF",
      },
      scheduleExpression: "cron(30 17 ? * 7#2 *)", // ๐Ÿ‘ˆ cron jon expression
      scheduleExpressionTimezone: "Canada/Mountain", // ๐Ÿ‘ˆ Specify the timezone to match your requirements.
      target: {
        arn: "arn:aws:scheduler:::aws-sdk:ec2:startInstances", // ๐Ÿ‘ˆ Api operation to call
        roleArn: schedulerRole.roleArn, // ๐Ÿ‘ˆ The role with permissions to perform this action.
        input: JSON.stringify({
          InstanceIds: [ParameterNames.EC2_INSTANCE_ID], // list of instances ID's to start
        }),
      },
    });

// Stop EC2 instance 5 Hours later

 new CfnSchedule(this, `${ParameterNames.PROJECT_NAME}-EC2-scheduler-stop`, {
      name: `${ParameterNames.PROJECT_NAME}-Stop`,
      flexibleTimeWindow: {
        mode: "OFF",
      },
      scheduleExpression: "cron(30 22 ? * 7#2 *)", 
      scheduleExpressionTimezone: "Canada/Mountain",
      target: {
        arn: "arn:aws:scheduler:::aws-sdk:ec2:stopInstances",
        roleArn: schedulerRole.roleArn,
        input: JSON.stringify({
          InstanceIds: [ParameterNames.EC2_INSTANCE_ID],
        }),
      },
    });

Github Repo: https://github.com/felipecubillos/cdk-start-stop-ec2-instances

Conclusion

Aws eventbridge scheduler + universal target is a great option in those scenarios that we have to trigger some API operations that do not required special management and we donโ€™t want to deal with custom code to develop and maintain.

References :

https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html

https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-targets-universal.html

3
Subscribe to my newsletter

Read articles from Andres Cubillos directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Andres Cubillos
Andres Cubillos

I'm a Software Developer who loves diving into the backend world, especially with AWS Services. You'll often find me coding away in Java, Javascript, and Python. Lately, I've been exploring the frontend world too, playing around with React. I'm all about sharing what I learn and spreading good vibes in the tech community!