AWS for DevOps — ECS Task Definitions

3 minute read

7.3 — ECS Task Definitions

A task definition is the blueprint for your containers on ECS. Think of it as a docker-compose.yml for AWS — it defines what image to run, CPU/memory, ports, environment variables, logging, and IAM roles.

Anatomy of a Task Definition

  Task Definition (my-app:5)
  ┌─────────────────────────────────┐
  │  Task Role: arn:...:role/app    │ ◀── permissions for your app code
  │  Execution Role: arn:...:role/e │ ◀── permissions for ECS agent
  │  Network Mode: awsvpc           │
  │  CPU: 512    Memory: 1024       │
  │                                  │
  │  Container Definitions:          │
  │  ┌───────────────────────┐      │
  │  │ Container: app        │      │
  │  │ Image: ECR/my-app:v1  │      │
  │  │ Port: 8080             │      │
  │  │ CPU: 256  Memory: 512  │      │
  │  │ Logs: CloudWatch       │      │
  │  └───────────────────────┘      │
  │  ┌───────────────────────┐      │
  │  │ Container: sidecar    │      │
  │  │ Image: ECR/envoy:v1   │      │
  │  │ Port: 9901             │      │
  │  │ CPU: 256  Memory: 512  │      │
  │  └───────────────────────┘      │
  └─────────────────────────────────┘

Registering a Task Definition (CLI)

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

task-def.json:

{
  "family": "my-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/myAppTaskRole",
  "containerDefinitions": [
    {
      "name": "app",
      "image": "123456789012.dkr.ecr.ap-south-1.amazonaws.com/my-app:v1",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        { "name": "APP_ENV", "value": "production" },
        { "name": "LOG_LEVEL", "value": "info" }
      ],
      "secrets": [
        {
          "name": "DB_PASSWORD",
          "valueFrom": "arn:aws:ssm:ap-south-1:123456789012:parameter/app/db-password"
        },
        {
          "name": "API_KEY",
          "valueFrom": "arn:aws:secretsmanager:ap-south-1:123456789012:secret:app/api-key-AbCdEf"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/my-app",
          "awslogs-region": "ap-south-1",
          "awslogs-stream-prefix": "app"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

Key Fields Explained

Field Purpose Example
family Logical name — revisions auto-increment my-app → my-app:1, my-app:2
networkMode Networking — awsvpc for Fargate awsvpc gives each task its own ENI
cpu / memory Task-level resources "512" = 0.5 vCPU, "1024" = 1 GB
executionRoleArn ECS agent permissions Pull images from ECR, write CloudWatch Logs
taskRoleArn Application permissions Read S3, call DynamoDB, send SQS messages
essential If true and container stops, task stops Main app = true, sidecars = depends

Fargate CPU / Memory Combinations

CPU (vCPU) Memory Options (GB)
0.25 0.5, 1, 2
0.5 1, 2, 3, 4
1 2, 3, 4, 5, 6, 7, 8
2 4–16 (in 1 GB increments)
4 8–30 (in 1 GB increments)

Invalid combinations cause registration errors. Example: cpu=256, memory=8192 is invalid.

Two IAM Roles — Don’t Confuse Them

Role Trust Who Uses It Permissions
Execution Role ecs-tasks.amazonaws.com ECS agent Pull ECR images, write CloudWatch Logs, read SSM/Secrets Manager
Task Role ecs-tasks.amazonaws.com Your application code Whatever your app needs (S3, DynamoDB, SQS, etc.)
  ┌────────────────────────────┐
  │       ECS Task              │
  │                             │
  │  Execution Role             │
  │  (used by ECS agent)        │
  │  - ecr:GetAuthorizationToken│
  │  - ecr:GetDownloadUrlFor... │
  │  - logs:CreateLogStream     │
  │  - ssm:GetParameters        │
  │                             │
  │  Task Role                  │
  │  (used by YOUR code)        │
  │  - s3:GetObject             │
  │  - dynamodb:PutItem         │
  │  - sqs:SendMessage          │
  └────────────────────────────┘

Secrets Injection

Source valueFrom Format
SSM Parameter Store arn:aws:ssm:REGION:ACCOUNT:parameter/path/to/param
Secrets Manager arn:aws:secretsmanager:REGION:ACCOUNT:secret:name-AbCdEf
Secrets Manager (specific key) arn:aws:secretsmanager:REGION:ACCOUNT:secret:name-AbCdEf:key::

Secrets are injected as environment variables at container startup — your app reads them like any env var.

Logging Configuration

{
  "logConfiguration": {
    "logDriver": "awslogs",
    "options": {
      "awslogs-group": "/ecs/my-app",
      "awslogs-region": "ap-south-1",
      "awslogs-stream-prefix": "app",
      "awslogs-create-group": "true"
    }
  }
}

Log streams follow the pattern: prefix/container-name/task-id

  /ecs/my-app
  └── app/app/abc123-def456-...
  └── app/app/ghi789-jkl012-...

Updating a Task Definition

Task definitions are immutable. To update, register a new revision:

# List current revisions
$ aws ecs list-task-definitions --family-prefix my-app
{
    "taskDefinitionArns": [
        "arn:aws:ecs:ap-south-1:123456789012:task-definition/my-app:1",
        "arn:aws:ecs:ap-south-1:123456789012:task-definition/my-app:2",
        "arn:aws:ecs:ap-south-1:123456789012:task-definition/my-app:3"
    ]
}

# Register a new revision (change the image tag)
# Edit task-def.json with new image tag, then:
$ aws ecs register-task-definition --cli-input-json file://task-def.json
# Creates my-app:4

Common Mistakes

Mistake Why It Hurts Fix
Confusing Execution Role vs Task Role App can’t access AWS services (or ECS can’t pull images) Execution Role → ECS agent; Task Role → your app
Invalid CPU/memory combo Task registration fails Check the Fargate combination table
Hard-coding secrets in environment Secrets in plaintext in task def Use secrets with SSM or Secrets Manager
No health check ECS can’t detect unhealthy containers Add healthCheck with proper startPeriod

Quick Reference

Task Command
Register task def aws ecs register-task-definition --cli-input-json file://task-def.json
Describe task def aws ecs describe-task-definition --task-definition NAME:REVISION
List families aws ecs list-task-definition-families
List revisions aws ecs list-task-definitions --family-prefix NAME
Deregister aws ecs deregister-task-definition --task-definition NAME:REVISION

Next → ECS Services & Scaling

Updated: