Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b4ee71a
feat(ecs_service): native ECS deployment strategies (rolling/blue_gre…
mabadir Jun 4, 2026
3c72a84
feat(ecs_service): make deployment strategy a per-deployment decision
mabadir Jun 4, 2026
6a8abef
ecs_service: address review findings on traffic-shift wiring
mabadir Jun 5, 2026
56b6f4a
Fix ECS infrastructure policy ARN
mabadir Jun 9, 2026
a849f7f
Ignore target group name changes for tg_1
mabadir Jun 9, 2026
73e7e4a
Merge branch 'main' into native-ecs-deployment-strategies
mabadir Jun 10, 2026
61909c3
default capacity provider
mabadir Jun 10, 2026
250bf02
update template
mabadir Jun 10, 2026
4f8fe87
update placeholder
mabadir Jun 10, 2026
69b2f01
remove the default provider
mabadir Jun 10, 2026
a733398
fixes
mabadir Jun 10, 2026
a395320
fix: omit ports on all-protocol security group rules
mabadir Jun 10, 2026
02541ed
test alb listener rule
mabadir Jun 11, 2026
bd9ac38
Merge branch 'main' into native-ecs-deployment-strategies
mabadir Jun 11, 2026
8791e90
add green_alb_listener_rule_enabled as tf var
mabadir Jun 11, 2026
4a8fd0e
add green_alb_listener rule
mabadir Jun 12, 2026
703a380
enable group stickiness
mabadir Jun 12, 2026
7a6eff5
test rule by default
mabadir Jun 13, 2026
b8cb146
Merge branch 'main' into native-ecs-deployment-strategies
mabadir Jun 13, 2026
4e2fc4a
update module
mabadir Jun 16, 2026
aa746f5
feat(ecs_service): configurable test-traffic selector for green liste…
mabadir Jun 16, 2026
7178ade
add deployment options
mabadir Jun 17, 2026
ecc72ee
Merge branch 'main' into native-ecs-deployment-strategies
mabadir Jun 17, 2026
ac45547
fix(ecs_service): avoid TG replacement deadlock on moved-block migration
mabadir Jun 17, 2026
3bcf91b
Merge branch 'main' into native-ecs-deployment-strategies
mabadir Jun 18, 2026
a649bf1
Fix ECS cluster capacity provider definition
mabadir Jun 18, 2026
e8965fa
Default ECS web test traffic to query string
mabadir Jun 18, 2026
9934440
Add ECS deployment input descriptions
mabadir Jun 18, 2026
86eb530
Clarify ECS traffic-shift deployment docs
mabadir Jun 19, 2026
24a5e1d
Document ALB group stickiness for ECS web service
mabadir Jun 19, 2026
3b7f51d
update to use item_description
mabadir Jun 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 36 additions & 17 deletions compute/ecs_cluster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,19 @@ module "ecs" {
private_subnet_ids = ["subnet-private-1", "subnet-private-2"]
public_subnet_ids = ["subnet-public-1", "subnet-public-2"]

# Enable all capacity providers
# Attach all capacity providers. AWS does not allow mixing Fargate and EC2
# providers in the cluster's default strategy, so the default strategy
# commits to a single family — EC2 here, since EC2 wins when enabled
# (override with capacity_provider_default). Services can still
# target FARGATE/FARGATE_SPOT via their own capacity_provider_strategies.
fargate_enabled = true
fargate_spot_enabled = true
fargate_weight = 1
fargate_spot_weight = 2

# EC2 for baseline capacity
ec2_instance_type = "t3.large"
ec2_min_size = 2
ec2_max_size = 20
ec2_desired_capacity = 2
ec2_weight = 1
ec2_base = 2 # Always run 2 tasks on EC2

# Both ALBs
public_alb_enabled = true
Expand Down Expand Up @@ -210,6 +210,7 @@ module "api_service" {
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|----------|
| container_insights_enabled | Enable CloudWatch Container Insights | `bool` | `true` | no |
| capacity_provider_default | Family for the cluster default strategy: `ec2`, `fargate` (includes Fargate Spot when enabled), or `fargate_spot`. AWS forbids mixing Fargate and EC2 providers in one strategy. Defaults to `ec2` if EC2 is enabled, then `fargate`, then `fargate_spot` | `string` | `null` | no |

### Fargate Capacity Provider

Expand Down Expand Up @@ -507,7 +508,7 @@ module "api_service" {
║ │ • ec2_capacity_provider_name = enable_ec2 ? "${var.name}-ec2" : null │ ║
║ │ │ ║
║ │ CAPACITY PROVIDER STRATEGY: │ ║
║ │ • capacity_provider_strategy = concat(fargate_strategy, fargate_spot_strategy, ec2_strategy) │ ║
║ │ • capacity_provider_strategy = single family via capacity_provider_default │ ║
║ │ │ ║
║ │ EC2 CONFIGURATION: │ ║
║ │ • ecs_user_data = base64encode(ECS_CLUSTER config + custom user_data) │ ║
Expand Down Expand Up @@ -690,7 +691,7 @@ module "api_service" {
║ │ ▼ ▼ ║
║ │ var.fargate_enabled ────►┌──────────────────────────────────────────────┐ ║
║ │ var.fargate_spot_enabled►│ aws_ecs_cluster_capacity_providers.this │ ║
║ │ local.enable_ec2 ──────►│ (FARGATE + FARGATE_SPOT + EC2 strategy) │ ║
║ │ local.enable_ec2 ──────►│ (single-family default strategy) │ ║
║ │ └──────────────────────────────────────────────┘ ║
║ │ ║
║ │ ┌────────────────────────────────────────────────────┐ ║
Expand Down Expand Up @@ -785,20 +786,33 @@ ECS supports three types of capacity providers, each with distinct trade-offs:
- You need specific instance types or kernel configurations
- You require persistent local storage

**Example: Cost-optimized mixed strategy**
**Example: Cost-optimized mixed cluster**

AWS does not allow a single capacity provider strategy to mix Fargate and EC2
(Auto Scaling group) providers, so the cluster's default strategy commits to
one family (`capacity_provider_default`). To mix families across
workloads, attach both to the cluster and pick the family per service:

```hcl
# Use EC2 for baseline, Fargate Spot for burst capacity
# EC2 is the cluster default; specific services opt into Fargate Spot
module "ecs" {
source = "..."

fargate_enabled = false # Disable standard Fargate
fargate_spot_enabled = true # Use Fargate Spot for overflow
fargate_spot_weight = 1
fargate_spot_enabled = true # Attached for services that want Spot

ec2_instance_type = "m5.large"
ec2_base = 5 # Always run 5 tasks on EC2
ec2_weight = 1
ec2_instance_type = "m5.large" # EC2 wins the default strategy when enabled
}

module "batch_service" {
source = ".../compute/ecs_service"

# ... service configuration ...

# Override the cluster default for this service only
capacity_provider_strategies = [
{ capacity_provider = "FARGATE_SPOT", weight = 1 }
]
}
```

Expand All @@ -813,8 +827,8 @@ The **base** and **weight** parameters control how ECS distributes tasks across
│ │
│ 1. First, satisfy BASE requirements (guaranteed tasks per provider) │
│ │
│ Example: fargate_base=2, ec2_base=3
│ → First 5 tasks: 2 on Fargate, 3 on EC2
│ Example: fargate_base=2, fargate_spot_weight=1
│ → First 2 tasks on Fargate, then split with Fargate Spot
│ │
│ 2. Then, distribute remaining tasks by WEIGHT ratio │
│ │
Expand All @@ -830,7 +844,11 @@ The **base** and **weight** parameters control how ECS distributes tasks across
|----------|---------------|--------|
| Fargate only | `fargate_enabled=true` | All tasks on Fargate |
| Cost savings | `fargate_weight=1, fargate_spot_weight=3` | 25% Fargate, 75% Fargate Spot |
| EC2 baseline | `ec2_base=5, ec2_weight=0, fargate_weight=1` | First 5 on EC2, rest on Fargate |
| EC2 default | `ec2_instance_type="m5.large"` | Default strategy is EC2; services may target Fargate via their own strategy |

Note: base/weight only combine providers within the same family (Fargate +
Fargate Spot). A strategy cannot mix Fargate and EC2 providers — the cluster
default commits to one family via `capacity_provider_default`.

### How does EC2 managed scaling work?

Expand Down Expand Up @@ -955,6 +973,7 @@ The module automatically creates a security group for EC2 instances that:
## Notes

- The EC2 capacity provider is only created when `ec2_instance_type` is specified
- The cluster default capacity provider strategy commits to a single family (AWS forbids mixing Fargate and EC2 providers in one strategy); control it with `capacity_provider_default`
- By default, uses the latest ECS-optimized Amazon Linux 2023 AMI
- EC2 instances automatically register with the ECS cluster via user data
- IMDSv2 is enforced by default for enhanced security
Expand Down
2 changes: 1 addition & 1 deletion compute/ecs_cluster/ec2.tf
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ module "ecs_instance_security_group" {
all_egress_enabled = true

# For ip_protocol="-1" (all protocols), AWS requires from_port/to_port to
# be omitted; use -1 here for caller clarity.
# be -1; setting them to 0 causes update failures.
ingress_rules = concat(
# Allow inbound from public ALB if enabled
var.public_alb_enabled ? [
Expand Down
24 changes: 16 additions & 8 deletions compute/ecs_cluster/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,22 @@ locals {
# EC2 capacity provider name
ec2_capacity_provider_name = local.enable_ec2 ? "${var.name}-ec2" : null

# Build capacity provider strategy based on enabled providers
capacity_provider_strategy = concat(
var.fargate_enabled ? [{
# Family used for the cluster default strategy. AWS rejects default
# strategies that mix Fargate and EC2 (ASG) capacity providers, so the
# default strategy must commit to a single family.
capacity_provider_default = coalesce(
var.capacity_provider_default,
local.enable_ec2 ? "ec2" : var.fargate_enabled ? "fargate" : "fargate_spot"
)

# Build the default capacity provider strategy from the selected family.
# FARGATE and FARGATE_SPOT may share a strategy; EC2 must stand alone.
capacity_provider_strategy = local.capacity_provider_default == "ec2" ? [{
capacity_provider = aws_ecs_capacity_provider.ec2[0].name
weight = var.ec2_weight
base = var.ec2_base
}] : concat(
local.capacity_provider_default == "fargate" && var.fargate_enabled ? [{
capacity_provider = "FARGATE"
weight = var.fargate_weight
base = var.fargate_base
Expand All @@ -35,11 +48,6 @@ locals {
capacity_provider = "FARGATE_SPOT"
weight = var.fargate_spot_weight
base = var.fargate_spot_base
}] : [],
local.enable_ec2 ? [{
capacity_provider = aws_ecs_capacity_provider.ec2[0].name
weight = var.ec2_weight
base = var.ec2_base
}] : []
)

Expand Down
4 changes: 2 additions & 2 deletions compute/ecs_cluster/rvn-ecs-cluster-definition.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update readme with instructions on how to access the standby environment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be in the web def

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I got this

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ definition:
name: ECS Cluster
description: Production-ready AWS ECS cluster with Fargate, Fargate Spot, optional EC2 capacity, and shared load balancers.
release:
version: 0.1.3
description: Fix all-protocol security group rule updates
version: 0.2.0
description: Automatically derive the default capacity provider so the cluster default strategy commits to a single provider family
Comment thread
flybayer marked this conversation as resolved.
module:
inputs:
- id: network
Expand Down
6 changes: 4 additions & 2 deletions compute/ecs_cluster/tests/basic.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -879,9 +879,11 @@ run "ec2_custom_weights" {
ec2_base = 0
}

# AWS rejects default strategies mixing Fargate and EC2 providers, so the
# default strategy commits to a single family (EC2 wins when enabled).
assert {
condition = length(aws_ecs_cluster_capacity_providers.this.default_capacity_provider_strategy) == 2
error_message = "Should have 2 capacity provider strategies (Fargate + EC2)"
condition = length(aws_ecs_cluster_capacity_providers.this.default_capacity_provider_strategy) == 1
error_message = "Default strategy should contain only the EC2 capacity provider when EC2 is enabled"
}
}

Expand Down
Loading
Loading