Here is some information about this architecture.
Here are the steps you can follow to build this solution on your own.
In this lab, you'll explore how to use EventBridge to schedule the starting and stopping of EC2 instances. This provides an efficient way to manage resources, ensuring that you only use and pay for what you need. It's a vital skill for optimizing cloud costs and resource utilization.
If you're using the Skillmix Labs feature, open the lab settings (the beaker icon) on the right side of the code editor. Then, click the Start Lab button to start hte lab environment.
Wait for the credentials to load. Then run this in the terminal.
Be sure to enter in your own access key and secret key and name your profile 'smx-lab'.
$ aws configure --profile smx-lab
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: us-west-2
Default output format [None]:
Note: If you're using your own AWS account you'll need to ensure that you've created and configured a named AWS CLI profile named smx-lab.
Next, we'll create the required_providers
config. This config is used to specify the required provider plugins for our Terraform project. In this case, we are specifying the aws
provider from HashiCorp with a minimum version of 4.64.0
.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.64.0"
}
}
}
Next, we'll create the aws config which is used to configure the AWS provider in Terraform. This config specifies the AWS profile to use (smx-lab) and the AWS region to operate in (specified by the variable var.region
).
provider "aws" {
profile = "smx-lab"
region = "${var.region}"
}
Next, we'll create the region config. This config is used to specify the AWS Region where we will be deploying our resources.
variable "region" {
type = string
description = "AWS Region where deploying resources"
default = "us-east-1"
}
Next, we'll create the aws_profile_name
config. This config is used to specify the AWS CLI credentials profile name. By default, it is set to default
.
variable "aws_profile_name" {
type = string
description = "AWS CLI credentials profile name"
default = "default"
}
Next, we'll create the vpc_cidr
config. This config is used to define the CIDR block for the VPC.
variable "vpc_cidr" {
type = string
description = "CIDR block for VPC"
default = "10.0.0.0/16"
}
Next, we'll create the subnet_cidr config. This config is used to define the CIDR block for the subnet. The default value is set to '10.0.0.0/24'.
variable "subnet_cidr" {
type=string
description = "CIDR block for the subnet"
default = "10.0.0.0/24"
}
Next, we'll create the aws_ami
config. This config is used to retrieve the most recent Amazon Linux 2 AMI that matches the specified filter criteria. The filter criteria include the owner alias being 'amazon' and the name starting with 'amzn2-ami-hvm'.
data "aws_ami" "amazon-linux-2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}
Next, we'll create the project_name config. This config is used to define the local variable project_name
with the value 'tf-test'
.
locals {
project_name = "tf-test"
}
Next, we'll create the aws_vpc config which is used to define an Amazon Virtual Private Cloud (VPC) in Terraform.
resource "aws_vpc" "vpc" {
cidr_block = "${var.vpc_cidr}"
}
Next, we'll create the aws_subnet config. This config is used to define a subnet in an AWS VPC.
resource "aws_subnet" "subnet" {
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${var.subnet_cidr}"
tags = {
Name = "private-subnet-1"
}
}
Next, we'll create the aws_instance
config. This config is used to create an EC2 instance in AWS.
resource "aws_instance" "test-ec2" {
ami = "${data.aws_ami.amazon-linux-2.id}"
instance_type = "t3.micro"
subnet_id = "${aws_subnet.subnet.id}"
tags = {
Name = "tf-test-ec2"
}
}
Next, we'll create the aws_scheduler_schedule
config. This config is used to define a schedule for starting EC2 instances.
resource "aws_scheduler_schedule" "ec2-start-schedule" {
name = "ec2-start-schedule"
flexible_time_window = [{"mode": "OFF"}]
schedule_expression = "cron(0 8 ? * MON-FRI *)"
schedule_expression_timezone= "US/Eastern"
description = "Start instances event"
target {
arn = "arn:aws:scheduler:::aws-sdk:ec2:startInstances"
role_arn = "${aws_iam_role.scheduler-ec2-role.arn}"
input = "${jsonencode({'InstanceIds': ['${aws_instance.test-ec2.id}']})}"
}
}
This config creates a scheduler schedule named ec2-start-schedule
that uses a cron expression to specify the time and days of the week when the schedule should run. It also sets the timezone to US/Eastern
. The schedule is associated with a target that specifies the ARN of the AWS SDK action to start EC2 instances. The target also references an IAM role and provides input in JSON format, specifying the instance IDs of the EC2 instances to start.
Next, we'll create the aws_scheduler_schedule
config. This config is used to define a schedule for stopping EC2 instances.
resource "aws_scheduler_schedule" "ec2-stop-schedule" {
name = "ec2-stop-schedule"
flexible_time_window = [{"mode": "OFF"}]
schedule_expression = "cron(0 17 ? * MON-FRI *)"
schedule_expression_timezone = "US/Eastern"
description = "Stop instances event"
target {
arn = "arn:aws:scheduler:::aws-sdk:ec2:stopInstances"
role_arn = "${aws_iam_role.scheduler-ec2-role.arn}"
input = "${jsonencode({'InstanceIds': ['${aws_instance.test-ec2.id}']})}"
}
}
This config creates a scheduler schedule named ec2-stop-schedule
that stops EC2 instances according to the specified cron expression. The flexible_time_window
is set to OFF
, meaning the schedule will not be flexible and will strictly adhere to the specified cron expression. The schedule_expression_timezone
is set to US/Eastern
to ensure the schedule is based on the Eastern Time Zone. The description
provides a brief description of the schedule.
The target
block specifies the action to be performed when the schedule is triggered. In this case, it stops instances using the arn
of the AWS SDK for EC2's stopInstances
function. The role_arn
references the ARN of the IAM role scheduler-ec2-role
that has the necessary permissions to perform the action. The input
parameter is a JSON-encoded string specifying the InstanceIds
of the EC2 instances to be stopped.
Next, we'll create the aws_iam_policy config. This config is used to define an IAM policy named 'scheduler_ec2_policy'. The policy allows the 'ec2:StartInstances' and 'ec2:StopInstances' actions on the specified EC2 instances.
resource "aws_iam_policy" "scheduler_ec2_policy" {
name = "scheduler_ec2_policy"
policy = "${jsonencode({
'Version': '2012-10-17',
'Statement': [
{
'Sid': 'VisualEditor0',
'Effect': 'Allow',
'Action': ['ec2:StartInstances', 'ec2:StopInstances'],
'Resource': ['${aws_instance.test-ec2.arn}:*', '${aws_instance.test-ec2.arn}']
}
]
})}"
}
Next, we'll create the aws_iam_role config. This config is used to create an IAM role in AWS called "scheduler-ec2-role". The role will have a managed policy attached to it, specified by the ARN of the "scheduler_ec2_policy" policy. The role will also have an assume role policy that allows the "scheduler.amazonaws.com" service to assume this role.
resource "aws_iam_role" "scheduler-ec2-role" {
name = "scheduler-ec2-role"
managed_policy_arns = ["${aws_iam_policy.scheduler_ec2_policy.arn}"]
assume_role_policy = "${jsonencode({
'Version': '2012-10-17',
'Statement': [
{
'Action': 'sts:AssumeRole',
'Effect': 'Allow',
'Sid': '',
'Principal': {
'Service': 'scheduler.amazonaws.com'
}
}
]
})}"
}
Deploy the Solution
Let's deploy this thing! If you haven't done so, start the Skillmix lab session and get the account credentials. Configure your Terraform environment to use those credentials.
Then, open a terminal or command prompt, navigate to the folder with your Terraform file, and execute these commands:
# initiatlize the project
$ terraform init
# show the plan
$ terraform plan
# apply the changes
$ terraform apply
Wait for the changes to be applied before proceeding.
Test the Solution
After deployment, view the schedule created in the Amazon EventBridge console under Scheduler>Schedules.
View the ec2-start-schedule
. Navigate to the Target tab and note the Payload
value which is in the format: {"InstanceIds":["i-006c2e9f4e706bf48"]}
Navigate to the EC2 console and find the EC2 instance from the Payload
value. Check the instance is powered on during 08:00 and 17:00 in the US/Eastern timezone.
Source: https://github.com/aws-samples/serverless-patterns/blob/main/eventbridge-schedule-to-ec2-terraform/variables.tf