Ravindra BagaleCourses & study guides मराठी

Chapter 56: Docker CI/CD with Jenkins and ECR, Deploy to Amazon ECS, Troubleshooting, Best Practices and Interview Questions

56.2 Deploy containers to Amazon ECS with Fargate

Friends, our image is now in ECR. But an image sitting in a registry serves no customer. We need something that runs it, keeps it running and replaces it when we release. Amazon ECS with Fargate does that without any server for us to manage. Today, step by step: cluster, task definition, logs, secrets, the service, the load balancer, a rolling deploy, a rollback, scaling and the errors you will meet.

1. Start from a story

At a Zomato-style food startup, the shop API ran on two EC2 servers. Every month someone had to patch the operating system, resize disks and restart Docker. One night a server ran out of disk and the API was down for an hour.

The team moved the API to ECS on Fargate. Now AWS runs the containers on machines the team never sees. They describe what to run in a task definition, and an ECS service keeps two copies running behind a load balancer.

When Jenkins pushes a new image, one command registers a new task definition revision and updates the service. ECS starts new containers, waits until they are healthy, then stops the old ones. Customers notice nothing.

Today we deploy the same API step by step.

Image in ECRshop-api:a1b2c3dTask definitionimage, cpu, memory, port, logsECS servicekeeps 2 tasks runningFargate tasksAWS runs the containersApplication Load Balancercustomers reach the API
Picture 1: the pieces of ECS

2. The foundations step by step

Step 1: Create a cluster

Why: A named group for services.

What: With Fargate, a cluster is just a name and a place to group services. There are no servers inside it to manage.

Example 1: Create

Type this:

aws ecs create-cluster --cluster-name shop --region ap-south-1 --query 'cluster.status' --output text

You will see:

ACTIVE

What it means: The cluster exists.

Example 2: List

Type this:

aws ecs list-clusters --region ap-south-1 --output text

You will see:

CLUSTERARNS arn:aws:ecs:ap-south-1:123456789012:cluster/shop

What it means: One cluster in the account.

Example 3: Describe

Type this:

aws ecs describe-clusters --clusters shop --region ap-south-1 --query 'clusters[0].[runningTasksCount,activeServicesCount]' --output text

You will see:

0 0

What it means: Empty for now.

Step 2: The task execution role

Why: How ECS pulls and logs.

What: ECS needs permission to pull from ECR, write logs to CloudWatch and read secrets. This is the task execution role. A separate task role gives your application its own AWS permissions.

Example 4: Create the role

Type this:

aws iam create-role --role-name ecsTaskExecutionRole --assume-role-policy-document file://ecs-trust.json --query Role.Arn --output text

You will see:

arn:aws:iam::123456789012:role/ecsTaskExecutionRole

What it means: The trust file lets ecs-tasks.amazonaws.com use this role.

Example 5: Attach the policy

Type this:

aws iam attach-role-policy --role-name ecsTaskExecutionRole --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy && echo ok

You will see:

ok

What it means: Pull images and write logs.

Example 6: Trust file content

Type this:

cat ecs-trust.json

You will see:

{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs-tasks.amazonaws.com"},"Action":"sts:AssumeRole"}]}

What it means: Only ECS tasks may assume it.

Step 3: A log group

Why: See what the container prints.

What: Containers on Fargate have no disk you can log in to. The awslogs driver sends everything the app prints to CloudWatch Logs.

Example 7: Create the log group

Type this:

aws logs create-log-group --log-group-name /ecs/shop-api --region ap-south-1 && echo created

You will see:

created

What it means: Logs will land here.

Example 8: Set retention

Type this:

aws logs put-retention-policy --log-group-name /ecs/shop-api --retention-in-days 14 && echo ok

You will see:

ok

What it means: Old logs deleted after 14 days to save money.

Example 9: Check

Type this:

aws logs describe-log-groups --log-group-name-prefix /ecs/shop --query 'logGroups[].[logGroupName,retentionInDays]' --output text

You will see:

/ecs/shop-api 14

What it means: Ready.

Step 4: A secret in Parameter Store

Why: Passwords never in the file.

What: Store the database password as a SecureString parameter. The task definition only holds its name, and ECS injects the value as an environment variable when the container starts.

Example 10: Store it

Type this:

aws ssm put-parameter --name /shop/db_pass --type SecureString --value 'example-only-pass' --query Version --output text

You will see:

1

What it means: Version 1 of the secret. Use your own value.

Example 11: Allow the role to read

Type this:

aws iam put-role-policy --role-name ecsTaskExecutionRole --policy-name read-shop-params --policy-document file://ssm-read.json && echo ok

You will see:

ok

What it means: Permission for ssm:GetParameters on /shop/*.

Example 12: Read without decrypting

Type this:

aws ssm get-parameter --name /shop/db_pass --query Parameter.Type --output text

You will see:

SecureString

What it means: The value stays encrypted.

3. Task definition and service step by step

Step 5: Write the task definition

Why: The recipe for one container.

What: The task definition says which image, how much CPU and memory, which port, which secrets and where logs go. Fargate needs networkMode awsvpc, so each task gets its own private IP.

Example 13: Main fields

Type this:

{
  "family": "shop-api",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "512", "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}

You will see:

(part of taskdef.json)

What it means: Half a vCPU and 1 GB memory.

Example 14: Container part

Type this:

"containerDefinitions": [{
  "name": "api",
  "image": "123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:a1b2c3d",
  "portMappings": [{"containerPort": 3000}],
  "secrets": [{"name": "DB_PASSWORD", "valueFrom": "arn:aws:ssm:ap-south-1:123456789012:parameter/shop/db_pass"}],
  "logConfiguration": {"logDriver": "awslogs", "options": {"awslogs-group": "/ecs/shop-api", "awslogs-region": "ap-south-1", "awslogs-stream-prefix": "api"}}
}]

You will see:

(part of taskdef.json)

What it means: Image, port, secret by name and logs.

Example 15: Register it

Type this:

aws ecs register-task-definition --cli-input-json file://taskdef.json --query 'taskDefinition.revision' --output text

You will see:

1

What it means: Revision 1 of shop-api.

Step 6: Add a container health check

Why: ECS must know when the app is ready.

What: A healthCheck inside the container definition runs a command every few seconds. If it keeps failing, ECS replaces the task. The image needs curl or wget for this.

Example 16: Health check JSON

Type this:

"healthCheck": {
  "command": ["CMD-SHELL", "curl -fs http://localhost:3000/health || exit 1"],
  "interval": 15, "timeout": 5, "retries": 3, "startPeriod": 20
}

You will see:

(part of the container definition)

What it means: Three failures in a row means unhealthy.

Example 17: Test it locally first

Type this:

docker run -d --name t -p 3000:3000 123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:a1b2c3d && sleep 3 && curl -fs localhost:3000/health

You will see:

{"status":"ok"}

What it means: The endpoint works before we trust ECS with it.

Example 18: Register revision 2

Type this:

aws ecs register-task-definition --cli-input-json file://taskdef.json --query 'taskDefinition.revision' --output text

You will see:

2

What it means: Each change is a new revision.

Step 7: Create the service behind an ALB

Why: Keep two copies running.

What: An ECS service keeps the desired number of tasks running and registers them in a target group of an Application Load Balancer. Tasks run in private subnets; only the ALB is public.

Example 19: Create the service

Type this:

aws ecs create-service --cluster shop --service-name shop-api --task-definition shop-api:2 --desired-count 2 --launch-type FARGATE --network-configuration 'awsvpcConfiguration={subnets=[subnet-0a1,subnet-0b2],securityGroups=[sg-0api],assignPublicIp=DISABLED}' --load-balancers 'targetGroupArn=arn:aws:elasticloadbalancing:ap-south-1:123456789012:targetgroup/shop-api/abc,containerName=api,containerPort=3000' --query service.status --output text

You will see:

ACTIVE

What it means: Two tasks are starting.

Example 20: Watch tasks

Type this:

aws ecs describe-services --cluster shop --services shop-api --query 'services[0].[runningCount,desiredCount]' --output text

You will see:

2 2

What it means: Both copies are running.

Example 21: Call through the ALB

Type this:

curl -s http://shop-alb-123.ap-south-1.elb.amazonaws.com/health

You will see:

{"status":"ok"}

What it means: Customers reach the container through the load balancer.

4. Releases step by step

Step 8: Rolling deploy of a new image

Why: Release without downtime.

What: To release, put the new image tag in the task definition, register a new revision and update the service. ECS starts new tasks, waits for health checks, then drains the old ones.

Example 22: Change the image tag

Type this:

sed -i 's/shop-api:a1b2c3d/shop-api:e4f5a6b/' taskdef.json && grep -o 'shop-api:[a-z0-9]*' taskdef.json

You will see:

shop-api:e4f5a6b

What it means: The new commit tag from Jenkins.

Example 23: Register and update

Type this:

REV=$(aws ecs register-task-definition --cli-input-json file://taskdef.json --query taskDefinition.revision --output text) && aws ecs update-service --cluster shop --service shop-api --task-definition shop-api:$REV --query service.taskDefinition --output text

You will see:

arn:aws:ecs:ap-south-1:123456789012:task-definition/shop-api:3

What it means: Rollout started.

Example 24: Wait until stable

Type this:

aws ecs wait services-stable --cluster shop --services shop-api && echo stable

You will see:

stable

What it means: The new version is fully live.

Step 9: Deployment circuit breaker and rollback

Why: Bad releases undo themselves.

What: Turn on the deployment circuit breaker. If new tasks keep failing, ECS stops the rollout and goes back to the last working revision automatically. You can also roll back by hand.

Example 25: Turn it on

Type this:

aws ecs update-service --cluster shop --service shop-api --deployment-configuration 'deploymentCircuitBreaker={enable=true,rollback=true},minimumHealthyPercent=100,maximumPercent=200' --query 'service.deploymentConfiguration.deploymentCircuitBreaker' --output text

You will see:

True True

What it means: Enable and rollback are both on.

Example 26: See deployments

Type this:

aws ecs describe-services --cluster shop --services shop-api --query 'services[0].deployments[].[status,rolloutState,taskDefinition]' --output text

You will see:

PRIMARY COMPLETED ...shop-api:3

What it means: The current rollout finished.

Example 27: Manual rollback

Type this:

aws ecs update-service --cluster shop --service shop-api --task-definition shop-api:2 --query service.taskDefinition --output text

You will see:

...task-definition/shop-api:2

What it means: Back to the previous revision in one command.

Step 10: Scale and auto scale

Why: More users, more tasks.

What: Change desired count by hand, or register the service with Application Auto Scaling so it adds tasks when average CPU goes above a target.

Example 28: Scale by hand

Type this:

aws ecs update-service --cluster shop --service shop-api --desired-count 4 --query service.desiredCount --output text

You will see:

4

What it means: Four copies now.

Example 29: Register a scalable target

Type this:

aws application-autoscaling register-scalable-target --service-namespace ecs --resource-id service/shop/shop-api --scalable-dimension ecs:service:DesiredCount --min-capacity 2 --max-capacity 10 && echo ok

You will see:

ok

What it means: Between 2 and 10 tasks.

Example 30: Target tracking on CPU

Type this:

aws application-autoscaling put-scaling-policy --service-namespace ecs --resource-id service/shop/shop-api --scalable-dimension ecs:service:DesiredCount --policy-name cpu60 --policy-type TargetTrackingScaling --target-tracking-scaling-policy-configuration '{"TargetValue":60,"PredefinedMetricSpecification":{"PredefinedMetricType":"ECSServiceAverageCPUUtilization"}}' --query PolicyARN --output text | cut -c1-40

You will see:

arn:aws:autoscaling:ap-south-1:12345678

What it means: Keeps average CPU near 60 percent.

Step 11: Read logs and debug a task

Why: When something goes wrong.

What: Logs are in CloudWatch. Stopped tasks keep a stoppedReason for a while. ECS Exec opens a shell inside a running Fargate task, like docker exec.

Example 31: Tail logs

Type this:

aws logs tail /ecs/shop-api --since 10m --follow

You will see:

2026-10-25T06:41:12 api/api/7f3e... listening on 3000

What it means: Live output from all tasks.

Example 32: Why did a task stop

Type this:

aws ecs describe-tasks --cluster shop --tasks 7f3e9c --query 'tasks[0].[stoppedReason,containers[0].exitCode]' --output text

You will see:

Essential container in task exited 1

What it means: Exit code 1 means the app crashed; read the logs.

Example 33: ECS Exec

Type this:

aws ecs execute-command --cluster shop --task 7f3e9c --container api --interactive --command 'sh'

You will see:

Starting session with SessionId: ecs-execute-command-0a1b
/app $

What it means: A shell inside the task. Needs enableExecuteCommand on the service.

Step 12: Deploy from the Jenkins pipeline

Why: One more stage after Push.

What: Add a Deploy stage to the Jenkinsfile from the last lesson. It swaps the tag in taskdef.json, registers a revision, updates the service and waits for stable. If ECS rolls back, the wait fails and Jenkins shows a red build.

Example 34: Deploy stage

Type this:

stage('Deploy') {
  steps {
    sh 'sed -i "s/shop-api:[a-z0-9]*/shop-api:$TAG/" taskdef.json'
    sh 'REV=$(aws ecs register-task-definition --cli-input-json file://taskdef.json --query taskDefinition.revision --output text) && aws ecs update-service --cluster shop --service shop-api --task-definition shop-api:$REV'
    sh 'aws ecs wait services-stable --cluster shop --services shop-api'
  }
}

You will see:

[Pipeline] sh
+ aws ecs wait services-stable ...
Finished: SUCCESS

What it means: Commit to live in one pipeline.

Example 35: Agent permission

Type this:

aws iam attach-role-policy --role-name jenkins-agent-role --policy-arn arn:aws:iam::123456789012:policy/ecs-deploy-shop && echo ok

You will see:

ok

What it means: A small custom policy: RegisterTaskDefinition, UpdateService, DescribeServices and iam:PassRole for the execution role.

Example 36: Check the running tag

Type this:

aws ecs describe-task-definition --task-definition shop-api --query 'taskDefinition.containerDefinitions[0].image' --output text

You will see:

123456789012.dkr.ecr.ap-south-1.amazonaws.com/shop-api:e4f5a6b

What it means: The live tag matches the Jenkins build.

Register revision 3new image tagECS starts new tasksold ones keep servingHealth checks passALB adds new tasksOld tasks drainedALB removes themDeployment COMPLETEDor automatic rollback
Picture 2: a rolling deploy

5. Common errors and how the team fixes them

Error one: CannotPullContainerError. The execution role lacks ECR permission, or private subnets have no NAT gateway or VPC endpoint to reach ECR.

Error two: ResourceInitializationError unable to retrieve secret. The execution role cannot read the SSM parameter.

Error three: tasks keep restarting with health check failures. The ALB health check path or port is wrong, or startPeriod is too short.

Error four: no logs at all. The log group name in the task definition does not match the real one.

Check yourself

Q1. What is the difference between task execution role and task role?

Execution role is for ECS to pull and log; task role is for your app's own AWS calls.

Q2. How do you release a new image?

Register a new task definition revision with the new tag and update the service.

Q3. What does the circuit breaker do?

Stops a failing rollout and rolls back to the last working revision.

Q4. Why awsvpc network mode?

Fargate gives each task its own network interface and private IP.

Friends, create the cluster, the roles, the log group and the secret, write the task definition with a health check, run it as a service behind an ALB, then release with a new revision and keep the circuit breaker on. Did you understand? Let us try it once more. Deploy your image, change one line of code, push through Jenkins and watch ECS roll it out.

Ravindra Bagale's Tip

Never put a password in the task definition environment section. Put it in Parameter Store or Secrets Manager and refer to it in secrets.

Lab: try at home

  1. Create an ECS cluster and the task execution role.
  2. Create a log group with 14 day retention.
  3. Store an example secret in Parameter Store.
  4. Register a task definition with a health check.
  5. Create a service with 2 tasks behind an ALB.
  6. Release a new image tag with a new revision.
  7. Turn on the circuit breaker and roll back by hand once.

Recap

  • Fargate runs containers without servers to manage.
  • Task definition is the recipe; the service keeps tasks running.
  • Secrets come from SSM by name; logs go to CloudWatch.
  • Release by registering a revision and updating the service.
  • Circuit breaker, auto scaling and ECS Exec keep it healthy.

Ravi Sir's Cards for this lesson

मराठी cards