ECS on Fargate
After this you can answer: How do a cluster, a service, a task definition and a task relate to each other?
Picture it
Section titled “Picture it”flowchart TB CL["cluster minitickets-dev"] --> SVC["service minitickets-dev-api<br/>desiredCount 1"] TD["task definition<br/>minitickets-dev-api:revision"] --> SVC SVC --> T["task: one api container<br/>+ Service Connect proxy"] SVC -->|"registers task IP"| TG["api target group"]The web side has the same shape: minitickets-dev-web.
How it works
Section titled “How it works”- The task definition says which image, how much CPU and memory, which env vars and secrets, and which roles. Every change makes a new numbered revision.
- The service starts tasks from the newest revision and keeps
desiredCountof them running. On a new revision it starts new tasks first, then stops the old ones. - Each task gets its own network card (awsvpc mode), a private IP, a security group and, here, a public IP.
- Health decides who lives. A task that fails its health checks is stopped and replaced. If new tasks never get healthy, the circuit breaker rolls back to the last working revision.
In MiniTickets
Section titled “In MiniTickets”| api | web | |
|---|---|---|
| Size (Fargate, ARM64) | 512 CPU, 1024 MB | 512 CPU, 1024 MB |
| Port | 4000 | 3000 |
| Roles | execution role + task role | execution role only |
| Health | container check on /health, ALB check on /health | ALB check on / |
Both services run one task on FARGATE_SPOT: spare AWS capacity, about 70% cheaper, which AWS may
take back with a 2-minute warning. Each has a 60 s health check grace period and the circuit breaker
with rollback (infra/src/compute/service.ts → createApiService).
Service Connect gives the two services private names in the namespace minitickets.internal:
the web server calls http://api:4000 to render /events, and the api calls http://web:3000 to
clear the web cache. A small proxy in each task listens on 14000 (api) and 13000 (web).
| From → to | What happens | What allows it |
|---|---|---|
| API ECS service → Public subnetsonly when computeEnabled = true | api tasks get a private and a public IP in a public subnet |
|
| API ECS service → ECS Service Connectonly when entryEnabled = true | api offers the name api and may call web |
|
| API ECS service → API security grouponly when computeEnabled = true | every API task (and the migration task) uses the api security group |
|
| API target group → API ECS serviceonly when entryEnabled = true | the ALB forwards to a healthy api task on port 4000 and checks GET /health |
|
| Web ECS service → API ECS serviceonly when entryEnabled = true | server-side rendering: the web server calls http://api:4000 |
|
| API ECS service → Web ECS serviceonly when entryEnabled = true | revalidate: POST http://web:3000/api/revalidate after an event or seat count changes |
|
| API ECS service → RDS Postgresonly when computeEnabled = true | SQL over TLS on port 5432 |
|
| API ECS service → ElastiCache Valkeyonly when computeEnabled = true | the Redis protocol over TLS (rediss://) on port 6379 |
|
| API ECS service → API task definitiononly when computeEnabled = true | the service starts tasks from the newest revision |
|
| API ECS service → ECS clusteronly when computeEnabled = true | the api service runs in cluster minitickets-dev on FARGATE_SPOT |
|
| API ECS service → API apponly when computeEnabled = true | each api task runs the Fastify server on port 4000 |
|
| API ECS service → ECR repositoriesonly when computeEnabled = true | ECS pulls the api image when a task starts |
|
| API ECS service → CloudWatch log groupsonly when computeEnabled = true | the awslogs driver sends every api line to /minitickets/dev/api |
|
| API ECS service → Booking-events SNS topiconly when computeEnabled = true | the outbox relay publishes each booking-confirmed event |
|
| API ECS service → Tickets tableonly when computeEnabled = true | reads one user's tickets for My tickets |
|
| API ECS service → Ticket assets bucketonly when computeEnabled = true | signs GET and PUT URLs, and copies a checked upload to posters/ |
|
| CD deploy job → API ECS serviceonly when computeEnabled = true | phase B pulumi up rolls the services; aws ecs wait services-stable |
|
| API ECS service → RDS master password secretonly when computeEnabled = true | ECS reads the database user and password when a task starts |
|
| API ECS service → Redis URL secretonly when computeEnabled = true | ECS reads REDIS_URL when a task starts |
|
| API ECS service → Revalidate secretonly when entryEnabled = true | ECS reads REVALIDATE_SECRET for the api when a task starts |
|
See it in AWS
Section titled “See it in AWS”ECS → Clusters → minitickets-dev → Services → minitickets-dev-api → Deployments, Events,
Tasks.
aws ecs describe-services --cluster minitickets-dev --services minitickets-dev-api
Break it
Section titled “Break it”| Symptom | Cause | Where to look |
|---|---|---|
| “circuit breaker triggered”, old version still runs | New tasks never got healthy | Service → Events |
| The api is down a minute, then back by itself | AWS took back the Spot capacity | Stopped task’s reason |
SSR times out calling http://api:4000 | No api-sg rule for TCP 14000 from web-sg | api-sg → Inbound rules |
Say it in an interview
Section titled “Say it in an interview”Follow-ups
Section titled “Follow-ups”What is the trade-off of Fargate Spot?
It is about 70% cheaper, but AWS can reclaim the capacity with two minutes’ warning. With one task, that means a short outage until the replacement is healthy. Production would run at least two tasks, partly on regular FARGATE.
Fargate or EC2 launch type?
Fargate: no servers to patch or scale, pay per task. EC2: cheaper at steady high load and more control, but we would manage the instances. For one small task each, Fargate wins.
Why do the web and api not call each other through the ALB?
In CloudFront mode the ALB accepts only requests with CloudFront’s secret header, and going out and back in would be slower. Service Connect keeps the call inside the VPC.
What does the 60-second grace period protect?
A task that is still starting fails its first health checks. Without the grace period, the service would kill it before it is ready, forever.
Advanced: Sizes, Exec and Container Insights
The api is 256 CPU / 512 MB when entry is off (no Service Connect proxy). Service Connect’s proxy
shares the task’s CPU and memory, which is why both tasks moved to 512 / 1024. ECS Exec is on for
the api, so ECS Exec can open a debug shell in the container; the task role carries the four
ssmmessages actions it needs. Container Insights is off on the cluster to avoid extra metric
costs (infra/src/compute/cluster.ts → createCluster).
Checkpoint
Section titled “Checkpoint”Answer these without scrolling up. If one feels hard, reread that section.
- What is the difference between a task definition and a task?
- What does a service do that a task started by hand does not?
- What happens when new tasks never become healthy?
- What are the costs and risks of FARGATE_SPOT?
- On which ports do the Service Connect proxies listen, and who may reach each?
Redraw it from memory: cluster, task definition, service, task and target group, with the arrow for each relation
Try this: on the map, select ECS Service Connect and find the two security group rules that make it work
Read this book online: https://book.theversehub.in/