Notice: Function WP_Scripts::add was called incorrectly. The script with the handle "markdown-renderer" was enqueued with dependencies that are not registered: mermaid-js, prism-core. Please see Debugging in WordPress for more information. (This message was added in version 6.9.1.) in /home/dataadl/www/wp-includes/functions.php on line 6131

AWS ECS Fargate: Complete Container Orchestration Guide

AWS Fargate is serverless compute for containers—you define tasks and services, and AWS manages the underlying infrastructure. Unlike EC2-backed ECS, there are no instances to patch, scale, or monitor. This guide covers production deployment patterns including load balancing, auto-scaling, secrets management, and cost optimization strategies from running 500+ Fargate tasks in production.

ECS Concepts

flowchart TB
    subgraph Cluster ["ECS Cluster"]
        subgraph Service1 ["Service: API (Desired: 3)"]
            Task1["Task 1"]
            Task2["Task 2"]
            Task3["Task 3"]
        end
        
        subgraph Service2 ["Service: Worker (Desired: 2)"]
            Task4["Task 4"]
            Task5["Task 5"]
        end
    end
    
    ALB["Application Load Balancer"] --> Service1
    SQS["SQS Queue"] --> Service2
    
    style Service1 fill:#E1F5FE,stroke:#0277BD
    style Service2 fill:#C8E6C9,stroke:#2E7D32
  • Task Definition: Template defining containers, resources, ports
  • Task: Running instance of a task definition
  • Service: Maintains desired count of tasks, integrates with ALB
  • Cluster: Logical grouping of services

Task Definition

{
  "family": "api-service",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/api-task-role",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/api:latest",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        { "name": "ASPNETCORE_ENVIRONMENT", "value": "Production" }
      ],
      "secrets": [
        {
          "name": "ConnectionStrings__Database",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:db-connection"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/api-service",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

Service with Auto-Scaling

resource "aws_ecs_service" "api" {
  name            = "api-service"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.api.arn
  desired_count   = 3
  launch_type     = "FARGATE"
  
  network_configuration {
    subnets          = var.private_subnet_ids
    security_groups  = [aws_security_group.api.id]
    assign_public_ip = false
  }
  
  load_balancer {
    target_group_arn = aws_lb_target_group.api.arn
    container_name   = "api"
    container_port   = 8080
  }
  
  deployment_configuration {
    maximum_percent         = 200
    minimum_healthy_percent = 100
  }
  
  # Enable Circuit Breaker for failed deployments
  deployment_circuit_breaker {
    enable   = true
    rollback = true
  }
}

resource "aws_appautoscaling_target" "api" {
  max_capacity       = 20
  min_capacity       = 3
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.api.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "api_cpu" {
  name               = "api-cpu-scaling"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.api.resource_id
  scalable_dimension = aws_appautoscaling_target.api.scalable_dimension
  service_namespace  = aws_appautoscaling_target.api.service_namespace
  
  target_tracking_scaling_policy_configuration {
    target_value       = 70.0
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
    scale_in_cooldown  = 300
    scale_out_cooldown = 60
  }
}

Cost Optimization

Fargate Spot

Use Spot for fault-tolerant workloads (workers, batch processing):

capacity_provider_strategy {
  capacity_provider = "FARGATE_SPOT"
  weight            = 2  # Prefer Spot
  base              = 0
}

capacity_provider_strategy {
  capacity_provider = "FARGATE"
  weight            = 1  # Fall back to On-Demand
  base              = 1  # Minimum 1 On-Demand task
}

Spot saves up to 70% but tasks may be interrupted with 2-minute warning.

Right-Sizing

Fargate charges based on configured CPU/memory, not consumption. Use Container Insights to find optimal sizes:

Common mistake: Setting 4 vCPU / 8 GB when task uses 0.5 vCPU / 1 GB
Cost: $116/month vs $14/month (88% savings)

Key Takeaways

  • Fargate eliminates EC2 instance management completely
  • Use Secrets Manager integration for credentials (never environment variables)
  • Enable deployment circuit breaker for automatic rollbacks
  • Target Tracking scaling is simplest for most workloads
  • Fargate Spot saves 70% for fault-tolerant workloads
  • Right-size tasks based on Container Insights metrics

Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.