Skip to content
Codeloom
AWS

Deploying to ECS Fargate

Deploy containerized apps to AWS ECS Fargate — task definitions, services, load balancers, auto-scaling, and CI/CD deployment.

·3 min read · By Codeloom
Intermediate 12 min read

What you'll learn

  • How ECS Fargate runs containers without managing servers
  • Task definitions, services, and clusters
  • Connecting an Application Load Balancer
  • Auto-scaling and deployment strategies

Prerequisites

  • Docker basics (Dockerfile, images)
  • AWS fundamentals (VPC, IAM, ECR)

ECS Fargate runs your Docker containers without managing EC2 instances. You define what to run (task definition), how many to run (service), and Fargate handles the infrastructure.

Architecture

ALB → ECS Service → Tasks (containers on Fargate)
                  → ECR (container images)
                  → CloudWatch (logs)

Push your image to ECR

# Create repository
aws ecr create-repository --repository-name my-app

# Login to ECR
aws ecr get-login-password | docker login --username AWS --password-stdin \
    123456789.dkr.ecr.us-east-1.amazonaws.com

# Build and push
docker build -t my-app .
docker tag my-app:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest

Task definition

A task definition is a blueprint for your container. Create task-definition.json:

{
  "family": "my-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "app",
      "image": "123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {"name": "NODE_ENV", "value": "production"}
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ]
}

Register it:

aws ecs register-task-definition --cli-input-json file://task-definition.json

Create a cluster and service

# Create cluster
aws ecs create-cluster --cluster-name my-cluster

# Create service
aws ecs create-service \
    --cluster my-cluster \
    --service-name my-app-service \
    --task-definition my-app \
    --desired-count 2 \
    --launch-type FARGATE \
    --network-configuration "awsvpcConfiguration={subnets=[subnet-abc,subnet-def],securityGroups=[sg-123],assignPublicIp=ENABLED}" \
    --load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,containerName=app,containerPort=8080"

Auto-scaling

# Register scalable target
aws application-autoscaling register-scalable-target \
    --service-namespace ecs \
    --resource-id service/my-cluster/my-app-service \
    --scalable-dimension ecs:service:DesiredCount \
    --min-capacity 2 \
    --max-capacity 10

# Target tracking policy — scale based on CPU
aws application-autoscaling put-scaling-policy \
    --service-namespace ecs \
    --resource-id service/my-cluster/my-app-service \
    --scalable-dimension ecs:service:DesiredCount \
    --policy-name cpu-scaling \
    --policy-type TargetTrackingScaling \
    --target-tracking-scaling-policy-configuration '{
        "TargetValue": 70.0,
        "PredefinedMetricSpecification": {
            "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
        }
    }'

Rolling deployments

Update the service to deploy a new image:

# Update task definition with new image tag
# Then update the service
aws ecs update-service \
    --cluster my-cluster \
    --service my-app-service \
    --task-definition my-app:2 \
    --deployment-configuration "maximumPercent=200,minimumHealthyPercent=100"

ECS performs a rolling deployment — it starts new tasks before stopping old ones.

Health checks

Configure health checks in the ALB target group:

aws elbv2 modify-target-group \
    --target-group-arn arn:aws:elasticloadbalancing:... \
    --health-check-path /health \
    --health-check-interval-seconds 30 \
    --healthy-threshold-count 2 \
    --unhealthy-threshold-count 3

Your container needs a /health endpoint:

@app.get("/health")
def health():
    return {"status": "healthy"}

Secrets from SSM/Secrets Manager

{
  "containerDefinitions": [{
    "secrets": [
      {
        "name": "DB_PASSWORD",
        "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789:secret:db-password"
      },
      {
        "name": "API_KEY",
        "valueFrom": "arn:aws:ssm:us-east-1:123456789:parameter/my-app/api-key"
      }
    ]
  }]
}

Summary

ECS Fargate removes server management from container deployments. Define your container in a task definition, run it as a service behind a load balancer, and let auto-scaling handle traffic spikes. Use ECR for image storage, CloudWatch for logs, and Secrets Manager for sensitive configuration.