UXDL Docs

AWS ECS

ECS task definitions, services, rolling deploys, and rollback.

Production backend services run on AWS ECS (Fargate). Docker images from Docker are pushed to ECR and deployed as ECS services behind an Application Load Balancer.

Architecture

Task definition

json
{
  "family": "backend-api",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::ACCOUNT:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::ACCOUNT:role/backend-api-task-role",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/backend-api:latest",
      "portMappings": [{ "containerPort": 4000, "protocol": "tcp" }],
      "healthCheck": {
        "command": ["CMD-SHELL", "wget -qO- http://localhost:4000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      },
      "environment": [
        { "name": "NODE_ENV", "value": "production" },
        { "name": "PORT", "value": "4000" }
      ],
      "secrets": [
        { "name": "DATABASE_URL", "valueFrom": "arn:aws:secretsmanager:..." },
        { "name": "FCM_PRIVATE_KEY", "valueFrom": "arn:aws:secretsmanager:..." }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/backend-api",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "api"
        }
      }
    }
  ]
}

The task role grants S3, SES, and Secrets Manager access. The execution role pulls ECR images and writes CloudWatch logs.

ECS service

json
{
  "serviceName": "backend-api",
  "cluster": "production",
  "taskDefinition": "backend-api",
  "desiredCount": 3,
  "launchType": "FARGATE",
  "loadBalancers": [
    {
      "targetGroupArn": "arn:aws:elasticloadbalancing:...",
      "containerName": "api",
      "containerPort": 4000
    }
  ],
  "deploymentConfiguration": {
    "minimumHealthyPercent": 100,
    "maximumPercent": 200,
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    }
  }
}

Deploy pipeline

bash
# 1. Build and push (CI does this on merge to main)
docker build -t backend-api:$TAG .
docker tag backend-api:$TAG $ECR_REPO:$TAG
docker push $ECR_REPO:$TAG
 
# 2. Register new task definition with updated image
aws ecs register-task-definition --cli-input-json file://task-definition.json
 
# 3. Update service — rolling deploy
aws ecs update-service \
  --cluster production \
  --service backend-api \
  --task-definition backend-api \
  --force-new-deployment
 
# 4. Wait for stability
aws ecs wait services-stable --cluster production --services backend-api

Rollback

bash
# List recent task definition revisions
aws ecs list-task-definitions --family-prefix backend-api --sort DESC
 
# Roll back to previous revision
aws ecs update-service \
  --cluster production \
  --service backend-api \
  --task-definition backend-api:42
 
aws ecs wait services-stable --cluster production --services backend-api

The deployment circuit breaker auto-rolls back if new tasks fail health checks.

Socket.io on ECS

  • ALB must support WebSocket upgrades (enabled by default on HTTP/HTTPS listeners)
  • Enable sticky sessions (target group stickiness) if running multiple tasks — optional but recommended for Socket.io
  • Health check path: /health

Environments

EnvironmentClusterDesired countNotes
Alphaalpha1Auto-deploy from develop
Betabeta2Deploy from release branch
Productionproduction3+Manual approval in CI

Official documentation