How to fully utilize Multi-AZ Capacity Reservations with On-Demand Fallback?
This article demonstrates flexible EC2 launches across Availability Zones that prioritize Capacity Reservations and falls back to on demand when needed to eliminate unnecessary charges and maximize capacity investments.
Introduction
Organizations running Amazon EC2 workloads such as High Performance Computing (HPC), Virtual Desktop Infrastructure (VDI) or similar compute-intensive workloads often need to guarantee compute capacity across multiple Availability Zones (AZs). Achieving this without adding operational complexity is a challenge. When running instances across multiple AZs, customers typically face these pain points:
- Manual AZ/subnet specification required at every launch - operators must know which AZ has available Capacity Reservation(CR) slots
- Underutilized Capacity Reservations - CRs in one AZ sit idle while instances launch in another AZ, thereby under utilizing the CR
These constraints force teams into sub optimal patterns like manually tracking CR availability across AZs before launch or over-provisioning CRs to avoid capacity shortfalls both of which increase cost and operational complexity. This challenge is compounded with dedicated tenancy, where CRs cannot be shared across accounts via AWS Resource Access Manager (RAM) - unlike shared tenancy reservations. This article demonstrates a system for AZ-agnostic instance launches into any available AZ without hard coding subnet IDs/AZ IDs, while ensuring Capacity Reservations are fully utilized and gracefully falling back to on-demand if reservations are full. This pattern is particularly valuable for organizations where a centralized platform team manages Capacity Reservations, so application owners can make a single API call without needing to know which AZ, subnet or specific reservation to target. This serves as a cost optimization best practice where reserved capacity is always consumed first, maximizing your existing investment and incurring on-demand charges only when necessary.
Solution Overview
The solution combines four components that work together to enable AZ-flexible launches with Capacity Reservation priority:
- On-Demand Capacity Reservations in multiple Availability Zones for the required instance type
- A Capacity Reservation Resource Group that pools those reservations into a single target
- An EC2 Launch Template configured with the Resource Group as its capacity target
- An EC2 Fleet request that uses the Launch Template to launch instances across AZs, consuming reserved capacity first and falling back to on-demand if reservations are full
Implementation instructions
For the purposes of this article, I am using t3.medium Linux EC2 instances with dedicated tenancy in the AWS Ireland region. This mechanism is equally applicable to shared-tenancy instances. All the steps can be configured using the AWS console, except Step 2 and 3.
Step 1: Create Capacity Reservations (One Per AZ)
# Update the command based on your required number of instances, instance type, operating system and tenancy
aws ec2 create-capacity-reservation \
--instance-type t3.medium \
--instance-platform Linux/UNIX \
--availability-zone eu-west-1a \
--instance-count 2 \
--tenancy dedicated \
--instance-match-criteria targeted
Repeat for each AZ (e.g., eu-west-1b, eu-west-1c).
Note: Use "targeted" match criteria so only instances explicitly targeting this CR consume the reserved capacity. You are charged for Capacity Reservations as soon as they are created, regardless of whether instances have been launched.
Step 2: Create a Capacity Reservation Resource Group
# Update the name of the Resource Group as required
aws resource-groups create-group \
--name "cr-resource-group" \
--configuration '{"Type":"AWS::EC2::CapacityReservationPool"}' '{"Type":"AWS::ResourceGroups::Generic", "Parameters": [{"Name": "allowed-resource-types", "Values": ["AWS::EC2::CapacityReservation"]}]}'
Step 3: Add Capacity Reservations to the Resource Group
List the Capacity Reservation ARNs to use them in the next CLI command:
aws ec2 describe-capacity-reservations \
--query "CapacityReservations[].CapacityReservationArn" \
--output table
Add each Capacity Reservation to the resource group:
# Update the command with your list of ARNs and update the group name from Step 2
aws resource-groups group-resources \
--group "cr-resource-group" \
--resource-arns \
arn:aws:ec2:eu-west-1:ACCOUNT_ID:capacity-reservation/cr-123 \
arn:aws:ec2:eu-west-1:ACCOUNT_ID:capacity-reservation/cr-345 \
arn:aws:ec2:eu-west-1:ACCOUNT_ID:capacity-reservation/cr-567
Step 4: Create a Launch Template targeting the Resource Group
Configure a Launch Template that references the resource group ARN - crucially, no AZ or subnet is specified:
# Update the command with the required template name, Image ID, Instance type, tenancy and Resource Group ARN
aws ec2 create-launch-template \
--launch-template-name "My_Template" \
--launch-template-data '{
"ImageId": "ami-xyz",
"InstanceType": "t3.medium",
"Placement": {
"Tenancy": "dedicated"
},
"CapacityReservationSpecification": {
"CapacityReservationTarget": {
"CapacityReservationResourceGroupArn": "arn:aws:resource-groups:eu-west-1:<YOUR_ACCOUNT_ID>:group/cr-resource-group"
}
}
}'
Step 5: Launch instances via EC2 Fleet
Use EC2 Fleet with the "use-capacity-reservations-first" strategy and AZ overrides. Save the following as fleet-config.json:
# Update the template name with what you configured in Step 4. Update the instance types, subnet IDs from your VPC.
{
"LaunchTemplateConfigs": [{
"LaunchTemplateSpecification": {
"LaunchTemplateName": "My_Template",
"Version": "$Latest"
},
"Overrides": [
{"InstanceType": "t3.medium", "AvailabilityZone": "eu-west-1a", "SubnetId": "subnet-aaa"},
{"InstanceType": "t3.medium", "AvailabilityZone": "eu-west-1b", "SubnetId": "subnet-bbb"},
{"InstanceType": "t3.medium", "AvailabilityZone": "eu-west-1c", "SubnetId": "subnet-ccc"}
]
}],
"TargetCapacitySpecification": {
"TotalTargetCapacity": 1,
"DefaultTargetCapacityType": "on-demand"
},
"OnDemandOptions": {
"AllocationStrategy": "lowest-price",
"CapacityReservationOptions": {
"UsageStrategy": "use-capacity-reservations-first"
}
},
"Type": "instant"
}
Launch with the CreateFleet API call"
aws ec2 create-fleet --cli-input-json file://fleet-config.json
Key parameters explained:
- Overrides: Lists all target AZs with their subnets - Fleet will try each
- "use-capacity-reservations-first": Prioritises CR slots before falling back to on-demand. If there are multiple unused Capacity Reservations, the allocation strategy (lowest-price or prioritized) is applied. If the number of unused Capacity Reservations is less than the requested target capacity, the remaining On-Demand target capacity is launched according to the allocation strategy (lowest-price or prioritized).
- "lowest-price" allocation: If multiple AZs have CRs available, picks the cheapest
- "Type": "instant": Synchronous launch which returns results immediately
Pricing Considerations
Capacity Reservations carries charges at the On-Demand/Savings Plans rate for the instance type whether used or not, from creation until cancelled. EC2 Fleet API calls, Launch Templates and Resource Groups are not charged - you only pay for the instances that are launched.
Important Considerations and Limitations
- Single-account constraint: Dedicated tenancy Capacity Reservations cannot be shared across accounts via AWS RAM. All CRs and the Fleet must operate within the same AWS account.
- Operating System support: Not all operating systems are supported in Capacity Reservations. Verify availability for your target instance type and region.
Conclusion
In this article, we replaced manual AZ tracking, hard coded subnets and unnecessary compute charges with a single and repeatable EC2 Fleet API call to maximize Capacity Reservation investments. This mechanism automatically finds and consumes available Capacity Reservations across Availability Zones before falling back to on-demand. We used Capacity Reservations to guarantee capacity, Resource Groups to pool them across Availability Zones, a Launch Template to define instance parameters and EC2 Fleet to orchestrate where and how instances are placed.
- Topics
- Compute
- Language
- English
Relevant content
- Accepted Answer
asked 4 years ago
