Skip to main content

What Is AWS ECS?

The Gap ECS Fills

You have a Docker image in ECR. How do you actually run it in production?

You could SSH into an EC2 instance and run docker run ... — but then you're back to managing uptime, restarts on crash, and manual deployments. ECS is AWS's answer to "run this container reliably, at scale, with minimal server management."

ECS Launch Types

With Fargate, AWS manages the underlying infrastructure completely. You specify CPU and memory requirements, and AWS provisions and manages the machines that run your containers. You never SSH into anything — there are no EC2 instances to patch or monitor.

EC2 Launch Type

With the EC2 launch type, you manage a cluster of EC2 instances. ECS schedules containers onto those instances. More control (specific instance types, GPU support) but more operational overhead.

Start with Fargate unless you have a specific reason not to.

Core Concepts

Cluster

A cluster is a logical grouping of ECS resources — it's the boundary within which your tasks and services run. One cluster can contain multiple services. Think of it as the "namespace" for your application.

Cluster: my-app-production
├── Service: api (3 tasks running)
└── Service: worker (2 tasks running)

Task Definition

A task definition is the blueprint for running a container — equivalent to docker run arguments, stored as a versioned JSON document. It specifies:

{
"family": "my-api",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "api",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app/api:v1.2.0",
"portMappings": [{ "containerPort": 3000 }],
"environment": [
{ "name": "NODE_ENV", "value": "production" }
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:ssm:us-east-1:123456789012:parameter/my-app/db-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-api",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}

Key fields:

  • cpu / memory — Fargate sizes in vCPU units (256 = 0.25 vCPU) and MB
  • image — the ECR URI (or Docker Hub image)
  • secrets — pull sensitive values from SSM Parameter Store at runtime (never hardcode secrets)
  • logConfiguration — sends container stdout/stderr to CloudWatch Logs automatically

Task

A task is a running instance of a task definition — one or more containers executing together. A task is to ECS what a pod is to Kubernetes.

Service

A service maintains a desired number of running tasks. If a task stops or crashes, the service starts a replacement. Services also integrate with load balancers to distribute traffic.

Service: api
desiredCount: 3 → ECS ensures 3 tasks are always running
loadBalancer: my-alb → ALB routes traffic to healthy tasks

The Full Deployment Flow

1. Build image locally: docker build -t my-app/api .
2. Push to ECR: docker push 123456789012.dkr.ecr.../my-app/api:v1.3.0
3. Update task definition: new revision pointing to :v1.3.0
4. Update ECS service: aws ecs update-service --task-definition my-api:5
5. ECS rolling update: starts new tasks with v1.3.0, drains and stops old ones
6. Load balancer: traffic shifts to new tasks only after health checks pass

This is a zero-downtime deployment — ECS never terminates old tasks until new tasks are healthy and serving traffic.

Secrets Management

Never put secrets in environment variables in the task definition — they'd be visible in the console. Use AWS SSM Parameter Store or Secrets Manager:

# Store the secret
aws ssm put-parameter \
--name "/my-app/database-url" \
--value "postgresql://user:password@host:5432/db" \
--type SecureString

# Reference it in the task definition (ECS injects it at runtime)
"secrets": [{ "name": "DATABASE_URL", "valueFrom": "/my-app/database-url" }]

The ECS task role needs ssm:GetParameters permission to read from SSM.

Load Balancer Integration

Attach an Application Load Balancer (ALB) to your ECS service:

  1. Create an ALB with a target group (type: IP, protocol: HTTP, port: 3000)
  2. In the ECS service configuration, select the ALB and target group
  3. ECS registers/deregisters task IPs with the target group automatically as tasks start and stop

The ALB handles health checks — only healthy tasks receive traffic.