Three ways to start/stop EC2 instances periodically
Consider how to start/stop EC2 instances periodically.
The first is to use EventBridge to periodically invoke Lambda functions for instance start/stop. This method is called “Instance Scheduler”.
https://aws.amazon.com/solutions/implementations/instance-scheduler-on-aws/?nc1=h_ls
The second is to define a maintenance window and periodically run the SSM Automation runbooks (AWS-StartEC2Instance, AWS-StopEC2Instance) for instance start/stop.
The third is to use the EventBridge Scheduler to periodically call the API for instance start/stop.
https://docs.aws.amazon.com/eventbridge/latest/userguide/scheduler.html
On this page, we will try the above three methods using CloudFormation.
Environment
Create three EC2 instances.
The OS will be the latest Amazon Linux 2023.
For each instance, configure the settings introduced at the beginning of this section.
Start/stop instances every 5 minutes.
The runtime environment for Lambda functions is Python 3.8.
CloudFormation template files
The above configuration is built with CloudFormation.
The CloudFormation templates are placed at the following URL
https://github.com/awstut-an-r/awstut-saa/tree/main/04/004
Explanation of key points of template files
How to use EventBridge and Lambda functions
Lambda Functions
Resources:
StartInstanceFunction:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
INSTANCE_ID: !Ref Instance
REGION: !Ref AWS::Region
Code:
ZipFile: |
import boto3
import os
instance_id = os.environ['INSTANCE_ID']
region = os.environ['REGION']
ec2_client = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
response = ec2_client.start_instances(
InstanceIds=(instance_id,)
)
print(response)
FunctionName: !Sub "${Prefix}-StartInstance"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole.Arn
Timeout: !Ref Timeout
StopInstanceFunction:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
INSTANCE_ID: !Ref Instance
REGION: !Ref AWS::Region
Code:
ZipFile: |
import boto3
import os
instance_id = os.environ['INSTANCE_ID']
region = os.environ['REGION']
ec2_client = boto3.client('ec2', region_name=region)
def lambda_handler(event, context):
response = ec2_client.stop_instances(
InstanceIds=(instance_id,)
)
print(response)
FunctionName: !Sub "${Prefix}-StopInstance"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole.Arn
Timeout: !Ref Timeout
Code language: YAML (yaml)
Create two Lambda functions.
One starts the instance, the other stops it.
Create a client object for boto3 EC2.
Execute the start_instances and stop_instances methods of this object.
The following are the IAM roles for both functions.
Resources:
FunctionRole:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: InstanceStartStopPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ec2:StartInstances
- ec2:StopInstances
Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)
The contents of the instance start/stop actions allowed.
EventBridge Rules
This page focuses on how to start and stop EC2 instances periodically.
For more information on how to use EventBridge rules to periodically invoke Lambda functions, please see the following page.
Resources:
StartInstanceScheduleRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: cron(0,10,20,30,40,50 * * * ? *)
State: ENABLED
Targets:
- Arn: !GetAtt StartInstanceFunction.Arn
Id: !Sub "${Prefix}-StartInstanceScheduleRule"
StopInstanceScheduleRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: cron(5,15,25,35,45,55 * * * ? *)
State: ENABLED
Targets:
- Arn: !GetAtt StopInstanceFunction.Arn
Id: !Sub "${Prefix}-StopInstanceScheduleRule"
Code language: YAML (yaml)
One is for starting and the other for stopping.
Each targets the aforementioned function.
Set the activation status with a cron expression.
Functions for startup are called at 0, 10, … 50 minutes every hour.
Function for stop calls every 5, 15, … 55 minutes of every hour.
The combination of these functions will repeat starting and stopping every 5 minutes.
If you use an EventBridge rule to make a Lambda function periodic, the EventBridge will invoke the function.
So you need to authorize EventBridge to call the function.
Resources:
StartInstanceFunctionPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt StartInstanceFunction.Arn
Principal: events.amazonaws.com
SourceArn: !GetAtt StartInstanceScheduleRule.Arn
Code language: YAML (yaml)
The above is the permission to invoke the function for starting, but the same applies for stopping.
Specify with EventBridge rules and Lambda functions.
How to use the SSM Automation runbook
Set up a maintenance window to periodically run the SSM Automation runbook.
For more information on this page, please see the following page.
Although not used in this case, the SSM Automation runbook can also be run periodically using the EventBridge rule.
Please refer to the following page for more information.
First, check the maintenance window.
Resources:
MaintenanceWindow1:
Type: AWS::SSM::MaintenanceWindow
Properties:
AllowUnassociatedTargets: true
Cutoff: 1
Description: StartInstance
Duration: 2
Name: !Sub "${Prefix}-MaintenanceWindow1"
Schedule: cron(0,10,20,30,40,50 * * * ? *)
ScheduleTimezone: Asia/Tokyo
Code language: YAML (yaml)
Above is the window for startup, but the same is true for stop.
The Schedule property allows you to specify when to execute the runbook.
The settings are the same as in the first method.
Next, check the targets in the maintenance window.
Resources:
MaintenanceWindowTarget1:
Type: AWS::SSM::MaintenanceWindowTarget
Properties:
Name: !Sub "${Prefix}-MaintenanceWindowTarget1"
ResourceType: INSTANCE
Targets:
- Key: InstanceIds
Values:
- !Ref Instance
WindowId: !Ref MaintenanceWindow1
Code language: YAML (yaml)
Specify an ID to define the target instance to start and stop.
Finally, confirm the task to be performed in the maintenance window.
Resources:
MaintenanceWindowTask1:
Type: AWS::SSM::MaintenanceWindowTask
Properties:
MaxConcurrency: 1
MaxErrors: 1
Name: !Sub "${Prefix}-MaintenanceWindowTask1"
Priority: 10
Targets:
- Key: WindowTargetIds
Values:
- !Ref MaintenanceWindowTarget1
TaskArn: AWS-StartEC2Instance
TaskInvocationParameters:
MaintenanceWindowAutomationParameters:
Parameters:
AutomationAssumeRole:
- !GetAtt SSMAutomationRole.Arn
InstanceId:
- "{{RESOURCE_ID}}"
TaskType: AUTOMATION
WindowId: !Ref MaintenanceWindow1
Code language: YAML (yaml)
For the startup task, specify the SSM Automation runbook AWS-StartEC2Instance.
For stopping, specify AWS-StopEC2Instance.
The following are the IAM roles in performing this task
Resources:
SSMAutomationRole:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- ssm.amazonaws.com
Policies:
- PolicyName: CreateImagePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ec2:StartInstances
- ec2:StopInstances
Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)
The contents of the instance start/stop actions allowed.
How to use EventBridge Scheduler
Resources:
StartInstanceSchedule:
Type: AWS::Scheduler::Schedule
Properties:
Description: StartInstance
FlexibleTimeWindow:
Mode: "OFF"
Name: !Sub "${Prefix}-StartInstanceSchedule"
ScheduleExpression: cron(0,10,20,30,40,50 * * * ? *)
State: ENABLED
Target:
Arn: arn:aws:scheduler:::aws-sdk:ec2:startInstances
Input: !Sub '{"InstanceIds": ["${Instance}"]}'
RoleArn: !GetAtt SchedulerRole.Arn
StopInstanceSchedule:
Type: AWS::Scheduler::Schedule
Properties:
Description: StopInstance
FlexibleTimeWindow:
Mode: "OFF"
Name: !Sub "${Prefix}-StopInstanceSchedule"
ScheduleExpression: cron(5,15,25,35,45,55 * * * ? *)
State: ENABLED
Target:
Arn: arn:aws:scheduler:::aws-sdk:ec2:stopInstances
Input: !Sub '{"InstanceIds": ["${Instance}"]}'
RoleArn: !GetAtt SchedulerRole.Arn
Code language: YAML (yaml)
The upper schedule is for startup and the lower schedule is for shutdown.
There are two points.
The first is the ScheduleExpression property.
Actions can be scheduled with this property.
This one also defines a schedule with a cron expression.
The second is the Target property.
Specify the API operation to be executed for the Arn property.
Arn – The complete service ARN, including the API operation you want to target, in the following format: arn:aws:scheduler:::aws-sdk:service:apiAction.
Using universal targets
The API for EC2 is specified with the following notation.
arn:aws:scheduler:::aws-sdk:ec2:[apiAction]
In this requirement, startInstances is performed for starting and stopInstances is performed for stopping.
Specify arguments for calling both APIs in the Input property.
Input – A well-formed JSON you specify with the request parameters that EventBridge Scheduler sends to the target API.
Using universal targets
The following page shows that when calling both APIs, just pass the ID of the target instance in InstanceIds.
https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html
https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html
The instance ID is passed to this property in JSON format.
The RoleArn property is described as follows
RoleArn – The ARN for the execution role you want to use for the target. The execution role you specify must have the permissions to call the API operation you want your schedule to target.
Using universal targets
Specify the following IAM roles
Resources:
SchedulerRole:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- scheduler.amazonaws.com
Policies:
- PolicyName: CreateImagePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ec2:StartInstances
- ec2:StopInstances
Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${Instance}"
Code language: YAML (yaml)
The contents of the instance start/stop actions allowed.
Architecting
Use CloudFormation to build this environment and check its actual behavior.
Create CloudFormation stacks and check the resources in the stacks
Create CloudFormation stacks.
For information on how to create stacks and check each stack, please see the following page.
After reviewing the resources in each stack, information on the main resources created in this case is as follows
- First configuration
- EC2 instance 1: i-0b9e6d15e61ee820c
- Lambda function 1: saa-04-004-StartInstance
- Lambda function 2: saa-04-004-StopInstance
- EventBridge Rule 1: saa-04-004-LambdaStack-HT-StartInstanceScheduleRul-RUFGLCMCBAMB
- EventBridge Rule 2: saa-04-004- LambdaStack-HT-StopInstanceScheduleRule-Q509A3N87K0U
- Second configuration
- EC2 instance 2: i-0c9f61ea77b7a59e4
- Maintenance window 1: mw-01d6f438ebac17258
- Maintenance window 2: mw-03e3e07dfcdd5a7fb
- Third configuration
- EC2 instance 3: i-0e54794687e579ba1
- EventBridge Scheduler 1: saa-04-004-StartInstanceSchedule
- EventBridge Scheduler 2: saa-04-004-StopInstanceSchedule
Now that you are ready, check each resource from the AWS Management Console.
First configuration
Check the Lambda function.
You can see that both functions have been successfully created.
Check EventBridge.
A rule is created to invoke a function every 10 minutes, with a 5-minute gap.
Second configuration
Check the status of the creation of the maintenance window.
Maintenance window for startup.
Maintenance window for stop.
Both are created successfully.
Third configuration
Scheduler for startup.
Scheduler for stop.
Both are created successfully.
Operation Check
Now that you are ready, check the EC2 instance.
Instance 1
Instance 2
Instance 3
Indeed, all three units start and stop repeatedly every 5 minutes.
All three methods were used to start and stop instances periodically.
Summary
We have introduced three methods for starting and stopping EC2 instances periodically.