Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 79 additions & 0 deletions MIGRATION_EC2_TO_FARGATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# EC2 to Fargate Migration Guide

## Configuration Changes

### 1. ECS Cluster (`ecs-cluster/terragrunt.hcl`)
```hcl
# Disable EC2 instances
ecs_cluster_instances_desired = 0
ecs_cluster_instances_autoscale_max = 0
# Optional: Enable ECS Exec logging
ecs_cluster_logging = true
```

### 2. Load Balancer (`load-balancer/terragrunt.hcl`)

⚠️ **Warning**: This change will break existing EC2 services using bridge mode on the same target group.

```hcl
# Required: Fargate uses awsvpc network mode
load_balancer_listener_ip_target = true
```

### 3. ECS Service (`service-app/terragrunt.hcl`)
```hcl
ecs_service_fargate = true
ecs_service_fargate_spot = false # Set true for 70% cost savings (tasks may be interrupted)

# Required: Specify CPU and memory (see valid combinations below)
ecs_service_cpu = 256
ecs_service_memory = 512

# Optional: Auto-scaling
ecs_service_desired_count = 2
ecs_use_fargate_scaling = true
ecs_fargate_min_capacity = 2
ecs_fargate_max_capacity = 10
ecs_fargate_cpu_target_value = 70
ecs_fargate_memory_target_value = 85
```

## Migration Steps

1. Update cluster:
```bash
cd ecs-cluster
terragrunt apply
```

2. Recreate service (causes brief downtime):
```bash
cd ../service-app
terragrunt taint module.ecs-service.aws_ecs_service.service
terragrunt apply
```

**Note**: Tainting is required because ECS services cannot change launch type in-place.

## Valid CPU/Memory Combinations

| CPU | Memory (MB) |
|-----|-------------|
| 256 | 512, 1024, 2048 |
| 512 | 1024, 2048, 3072, 4096 |
| 1024 | 2048-8192 (1GB increments) |
| 2048 | 4096-16384 (1GB increments) |
| 4096 | 8192-30720 (1GB increments) |

## Troubleshooting

**Invalid CPU or memory value**
- Check your CPU/memory combination against the table above

**Target group health check failing**
- Ensure `load_balancer_listener_ip_target = true`
- Verify security groups allow traffic from load balancer

**Tasks not starting**
- Check CloudWatch logs: `/ecs/<cluster-name>/exec`
- Verify subnet has internet access (NAT gateway or public IP)
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# terraform-aws-ecs-cluster for terraform >= 0.12

This module configures ECS-cluster consisting of number of ec2 instances. It supports spot ec2 instances, which might be
cost effective for a development environment that allows some downtime.
This module creates an ECS cluster supporting EC2 instances, Fargate, and Fargate Spot capacity providers.

## Required variables

Only `cluster_name` is required to be set.
Only `cluster_name` is required.

## Enabling Fargate

The cluster registers FARGATE, FARGATE_SPOT, and EC2 capacity providers. To use Fargate exclusively, set EC2 instances to 0:

```hcl
ecs_cluster_instances_desired = 0
ecs_cluster_instances_autoscale_max = 0
```

Services can then use Fargate by setting `ecs_service_fargate = true`. See `MIGRATION_EC2_TO_FARGATE.md` for migration steps.
68 changes: 61 additions & 7 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,75 @@ resource "aws_ecs_capacity_provider" "autoscale" {

resource "aws_ecs_cluster" "main" {
name = var.cluster_name

dynamic "configuration" {
for_each = var.cluster_logging ? [1] : []

content {
execute_command_configuration {
logging = "OVERRIDE"

log_configuration {
cloud_watch_log_group_name = aws_cloudwatch_log_group.ecs_exec_logs[0].name
}
}
}
}
}

resource "aws_cloudwatch_log_group" "ecs_exec_logs" {
count = var.cluster_logging ? 1 : 0
name = "/ecs/${var.cluster_name}/exec"
retention_in_days = var.cluster_log_retention_days
}

resource "aws_ecs_cluster_capacity_providers" "providers" {
cluster_name = aws_ecs_cluster.main.name

capacity_providers = compact([
capacity_providers = distinct(compact([
var.instances_autoscale_max > 0 && var.instances_desired == 0 ? aws_ecs_capacity_provider.autoscale[0].name : "",
"FARGATE",
"FARGATE_SPOT",
])
]))


default_capacity_provider_strategy {
base = 1
weight = 100
capacity_provider = var.instances_autoscale_max > 0 && var.instances_desired == 0 ? aws_ecs_capacity_provider.autoscale[0].name : "FARGATE"
dynamic "default_capacity_provider_strategy" {
for_each = var.cluster_strategy_type == "default" ? [1] : []
content {
base = 1
weight = 100
capacity_provider = var.instances_autoscale_max > 0 && var.instances_desired == 0 ? aws_ecs_capacity_provider.autoscale[0].name : "FARGATE"
}
}
}

dynamic "default_capacity_provider_strategy" {
for_each = var.cluster_strategy_type == "fargate" ? [1] : []
content {
base = 0
weight = 1
capacity_provider = "FARGATE"
}
}

dynamic "default_capacity_provider_strategy" {
for_each = var.cluster_strategy_type == "fargate_spot" ? [1] : []
content {
base = 0
weight = 1
capacity_provider = "FARGATE_SPOT"
}
}

dynamic "default_capacity_provider_strategy" {
for_each = var.cluster_strategy_type == "fargate_spot_with_fallback" ? [
{ base = 1, weight = 0, provider = "FARGATE" },
{ base = 0, weight = 1, provider = "FARGATE_SPOT" }
] : []
content {
base = default_capacity_provider_strategy.value.base
weight = default_capacity_provider_strategy.value.weight
capacity_provider = default_capacity_provider_strategy.value.provider
}
}

}
30 changes: 29 additions & 1 deletion variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,36 @@ variable "vpc_name" {
default = ""
}

variable "cluster_logging" {
description = "Enable logging for ECS cluster. Set to true to enable."
type = bool
default = false
}

variable "cluster_log_retention_days" {
description = "Number of days to retain ECS Exec logs. Set to 0 for never expire."
type = number
default = 30
}

variable "cluster_strategy_type" {
description = <<-EOD
Defines the ECS capacity provider strategy. Possible values are:
- "default": Uses the default capacity provider strategy defined in the ECS cluster.
- "fargate": Preferentially uses Fargate for task deployments.
- "fargate_spot": Preferentially uses Fargate Spot for task deployments.
- "fargate_spot_with_fallback": Uses Fargate Spot by default but ensures at least one task runs on Fargate as a fallback.
EOD
type = string
default = "default"

validation {
condition = contains(["default", "fargate", "fargate_spot", "fargate_spot_with_fallback"], var.cluster_strategy_type)
error_message = "Invalid ECS strategy type. Allowed values are 'default', 'fargate', 'fargate_spot', 'fargate_spot_with_fallback'."
}
}
variable "disk_kms_key_id" {
type = string
description = "KMS key ID or ARN for EBS volume encryption. Use full ARN for custom keys. AWS managed key used if not specified."
default = ""
}
}