EthicsComputerCourses
Join training +91 90532 10052

Containers: ECR, ECS & Fargate

AWS · Lesson 28 of 42 Advanced 7 min read Updated

A container image packages your app with its exact runtime and libraries, so it runs the same on your laptop, a colleague's machine and the cloud. AWS has three services that matter most for containers: Amazon ECR stores images, Amazon ECS runs and manages containers, and AWS Fargate provides the compute so you never manage servers.

In this lesson you will push an image to ECR, describe it in an ECS task definition for Fargate, run it as a service behind a load balancer, and see when to use ECS Express Mode or Kubernetes on EKS instead. You should already know what a Docker image and container are.

Amazon ECR: your private image registry

Elastic Container Registry (ECR) hosts private repositories of container images, close to where they run. It can scan images for known vulnerabilities, keep tags immutable so 1.0 always means the same image, and delete old images with lifecycle policies.

Terminal
aws ecr create-repository --repository-name tiffin-api \
  --image-scanning-configuration scanOnPush=true \
  --image-tag-mutability IMMUTABLE \
  --query repository.repositoryUri --output text
Output
111122223333.dkr.ecr.ap-south-1.amazonaws.com/tiffin-api

Docker must log in to ECR before pushing. The CLI produces a temporary password and pipes it straight into docker login, so it never appears on screen:

Terminal
aws ecr get-login-password --region ap-south-1 | docker login --username AWS \
  --password-stdin 111122223333.dkr.ecr.ap-south-1.amazonaws.com

docker build -t tiffin-api:1.0 .
docker tag tiffin-api:1.0 111122223333.dkr.ecr.ap-south-1.amazonaws.com/tiffin-api:1.0
docker push 111122223333.dkr.ecr.ap-south-1.amazonaws.com/tiffin-api:1.0
Output
Login Succeeded

The full image URI has the form account.dkr.ecr.region.amazonaws.com/repository:tag. If you build on an Apple Silicon Mac or a Graviton machine, the image is arm64; build for the architecture you will run on.

Amazon ECS concepts

  • Cluster: a logical group for your containers in one Region.
  • Task definition: a JSON blueprint for one or more containers: image, CPU, memory, ports, environment variables, IAM roles and logging. Each change creates a new numbered revision.
  • Task: one running copy of a task definition.
  • Service: keeps a chosen number of tasks running, replaces failed ones, registers them with a load balancer and rolls out new revisions.
  • Capacity: where tasks run. Fargate is serverless: each task gets its own isolated compute. EC2 capacity runs tasks on instances you manage.

A task definition for Fargate

This task definition, taskdef.json, runs the tiffin API container on Fargate with a quarter vCPU and 512 MB of memory on Graviton:

JSON
{
  "family": "tiffin-api",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "runtimePlatform": { "cpuArchitecture": "ARM64", "operatingSystemFamily": "LINUX" },
  "executionRoleArn": "arn:aws:iam::111122223333:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::111122223333:role/tiffin-api-task-role",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "111122223333.dkr.ecr.ap-south-1.amazonaws.com/tiffin-api:1.0",
      "essential": true,
      "portMappings": [{ "containerPort": 8080, "protocol": "tcp" }],
      "environment": [{ "name": "GST_PERCENT", "value": "5" }],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/tiffin-api",
          "awslogs-region": "ap-south-1",
          "awslogs-stream-prefix": "api"
        }
      }
    }
  ]
}

Points to notice:

  • Fargate requires networkMode awsvpc: every task gets its own network interface, private IP address and security groups.
  • cpu and memory are strings, and only certain combinations are allowed, from 0.25 vCPU up to 16 vCPU.
  • The execution role lets ECS pull the image from ECR and write logs. The task role is what your code uses to call AWS services, like a Lambda execution role. Keep them separate.
  • The awslogs driver sends container output to CloudWatch Logs.

Register it:

Terminal
aws ecs register-task-definition --cli-input-json file://taskdef.json \
  --query taskDefinition.taskDefinitionArn --output text
Output
arn:aws:ecs:ap-south-1:111122223333:task-definition/tiffin-api:1

Run it as a service

Create a cluster and a service with two tasks in private subnets, registered with an Application Load Balancer's target group:

Terminal
aws ecs create-cluster --cluster-name tiffin

aws ecs create-service --cluster tiffin --service-name tiffin-api \
  --task-definition tiffin-api:1 --desired-count 2 --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-0app1a000000000a,subnet-0app1b000000000b],securityGroups=[sg-0web234567890abcd],assignPublicIp=DISABLED}" \
  --load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:ap-south-1:111122223333:targetgroup/tiffin-api/0123456789abcdef,containerName=api,containerPort=8080" \
  --query "service.{Name: serviceName, Desired: desiredCount, Status: status}"
Output
{
    "Name": "tiffin-api",
    "Desired": 2,
    "Status": "ACTIVE"
}

The two tasks run in two Availability Zones. To deploy version 1.1, push the new image, register a new task definition revision and run aws ecs update-service --cluster tiffin --service tiffin-api --task-definition tiffin-api:2; ECS replaces tasks gradually and can roll back automatically if new tasks fail health checks. Tasks in private subnets need a NAT gateway or VPC endpoints (for ECR, S3 and CloudWatch Logs) to pull images.

The shortcut: ECS Express Mode

Building the load balancer, target group, security groups and auto scaling yourself is a lot of work for a simple web service. Amazon ECS Express Mode, launched in late 2025, does it from a container image plus two IAM roles: it creates a Fargate service, an Application Load Balancer with an AWS-provided URL, canary deployments and auto scaling, while leaving every resource visible and editable in your account. It is AWS's recommended replacement for App Runner, and you can use it from the console, the CLI or infrastructure as code.

Kubernetes on Amazon EKS

Amazon Elastic Kubernetes Service (EKS) runs managed Kubernetes. Choose it when your team already uses Kubernetes tools (kubectl, Helm) or needs to run the same platform across clouds and data centres. EKS Auto Mode lets AWS manage the worker nodes, scaling and core add-ons. For a first containerised app on AWS, ECS is usually simpler to learn and operate.

Common mistakes

  • Mixing up the execution role and the task role, so the app gets ECR permissions or cannot reach DynamoDB.
  • Building arm64 images and running them on X86_64 tasks (or the reverse), giving "exec format error".
  • Using the latest tag in production. Use immutable version tags so you know exactly what is running.
  • Public IPs on tasks to reach ECR, instead of private subnets with NAT or VPC endpoints.
  • Logging nothing. Without logConfiguration, container output is lost.

Key points

  • ECR stores private images; log in with aws ecr get-login-password piped to docker login.
  • ECS runs containers using clusters, task definitions (blueprints), tasks (running copies) and services (keep tasks running).
  • Fargate is serverless container compute: awsvpc networking, CPU and memory set per task.
  • The execution role pulls images and writes logs; the task role gives your code AWS permissions.
  • ECS Express Mode builds a full web service from an image and replaces App Runner for new users.
  • EKS (with Auto Mode) is the choice when you need Kubernetes.

Exercise

Write a Fargate task definition for a container exam-results-web that uses the image 111122223333.dkr.ecr.ap-south-1.amazonaws.com/exam-results:2.3, listens on port 3000, has 0.5 vCPU and 1 GB memory on x86_64, and logs to /ecs/exam-results.

Show solution
JSON
{
  "family": "exam-results-web",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "runtimePlatform": { "cpuArchitecture": "X86_64", "operatingSystemFamily": "LINUX" },
  "executionRoleArn": "arn:aws:iam::111122223333:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "111122223333.dkr.ecr.ap-south-1.amazonaws.com/exam-results:2.3",
      "essential": true,
      "portMappings": [{ "containerPort": 3000, "protocol": "tcp" }],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/exam-results",
          "awslogs-region": "ap-south-1",
          "awslogs-stream-prefix": "web"
        }
      }
    }
  ]
}

In ECS, 1024 CPU units equal one vCPU, so 0.5 vCPU is "512", and memory is given in MiB, so 1 GB is "1024". A task role is only needed if the app itself calls AWS services.

Quick Quiz

1. Which ECS object is a JSON blueprint describing containers, CPU, memory and roles?

2. Which network mode does Fargate require?

3. Your container cannot read from DynamoDB, but the image pulls fine. Which role needs the permission?

4. What does ECS Express Mode create from a container image?

Learn AWS with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call