Containers: ECS, Fargate and EKS
What a container is and how it differs from a virtual machine, storing images in ECR, running them with ECS on Fargate, the difference between the two IAM roles, when to choose EKS, and a hands-on where a service replaces a stopped task.
- Key idea
- Definition
- When to use
- Caution
In this article
In part nineteen we separated the services from each other. Each service still needs somewhere to run, and on an EC2 server that means an image, updates, libraries and the famous sentence: "it works on my machine".
Containers solve this: you package the application with everything it needs in one unit, and it runs the same way on your laptop and in production.
What's a container?
A container is an isolated process with its own files and libraries, which shares the host's operating system instead of carrying its own.
| Virtual machine | Container | |
|---|---|---|
| Contains | A full operating system and the application | The application and its libraries |
| Size | Gigabytes | Often megabytes |
| Startup | Minutes | Seconds |
| Isolation | Stronger, with a separate system | Lighter, with a shared kernel |
Image, container and registry
Three words you'll keep hearing:
- Image: a read-only package of the application and its libraries, like a recipe.
- Container: a running copy of an image. One image can run as a thousand containers.
- Registry: where images are stored, such as Docker Hub or Amazon ECR.
The most common tool for building images is Docker. You write what the image contains in a Dockerfile:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
Then you build it, try it on your machine, and push it to a registry:
docker build -t shop .
docker run -p 8080:80 shop
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/shop
Amazon ECR: your images' home
ECR (Elastic Container Registry) is AWS's image registry, with storage on S3 behind the scenes:
- Private repositories: access to them goes through IAM, so a server or task needs permission to pull.
- Public repositories: anyone can pull from them, through the ECR Public Gallery.
- Extras: image scanning for vulnerabilities, versions with tags, and lifecycle rules that delete old images.
Amazon ECS: AWS's way of running containers
ECS (Elastic Container Service) takes your images and runs them, keeps them running, and places them behind a load balancer. It's AWS's own service, simpler than Kubernetes, and the service itself has no extra charge. You pay for the capacity it runs on.
Four terms cover the whole service:
| Term | Meaning | Comparable to |
|---|---|---|
| Cluster | A logical group that tasks run in | Your fleet of servers |
| Task definition | A recipe: the image, CPU, memory, ports and roles | A launch template |
| Task | One or more running containers from that recipe | A server |
| Service | Keeps a set number of tasks running, and replaces failed ones | An Auto Scaling group |
Who runs the containers?
Containers need computing capacity, and you have three options:
| Option | Who manages the servers | Suits |
|---|---|---|
| Fargate | AWS entirely, with no servers to see | Most applications; start here |
| Managed Instances | AWS manages them, and you choose the instance types | Needing GPUs or specific instances without the management |
| EC2 | You, through an Auto Scaling group | Full control, or reducing the cost of steady load |
With Fargate you state the CPU and memory for a task, and pay for those while it runs. Fargate Spot cuts the price sharply for tasks that can tolerate interruption, in the same way as Spot servers.
Two IAM roles, and confusing them is a classic
Every Fargate task can have two roles, and they do different jobs:
| Role | Who uses it | Example |
|---|---|---|
| Task execution role | ECS itself, to prepare the task | Pulling the image from ECR and sending logs to CloudWatch |
| Task role | Your code inside the container | Reading from S3 or writing to DynamoDB |
If the task fails at startup with a pull error, look at the execution role. If your code gets AccessDenied while it's running, look at the task role. And give each service its own task role, not one shared role.
Network and load balancing
On Fargate each task gets its own network interface and private IP, so it has its own security group like a server. Put an Application Load Balancer in front of the service, and it registers new tasks automatically and removes failed ones. It suits most web applications, and you'd choose a Network Load Balancer for very high throughput or fixed IP addresses.
Storage
A container's disk disappears with it. To share files between tasks, mount EFS, which works on both Fargate and EC2. And for anything that matters, store it outside the container in S3 or a database.
Scaling
Service Auto Scaling changes the number of tasks based on average CPU or memory, requests per task from the load balancer, or a schedule. The policies are the same ones we saw in part seven.
On Fargate that's all you need. With EC2 there's a second layer, because you need servers for the new tasks to land on. A capacity provider links the service to an Auto Scaling group and adds servers when tasks need them.
Not just web services
Tasks don't have to stay running. Three common patterns:
| Pattern | How it works |
|---|---|
| Reacting to an event | A file lands in S3, EventBridge starts a Fargate task to process it, and it stops when done |
| Scheduled work | EventBridge Scheduler starts a task every night for a batch job |
| Queue workers | A service pulls from SQS, and scales by the number of messages waiting |
ECS Express Mode: the short way
Just want a web application from an image, without setting up every piece? ECS Express Mode takes an image and two roles, and creates the Fargate service, load balancer, health checks, scaling and a link. All of it stays in your account, so you can customize it later.
Amazon EKS: Kubernetes
Kubernetes is an open-source system for running containers, widely used across clouds and data centers. EKS (Elastic Kubernetes Service) runs its control plane for you, across several Availability Zones, at $0.10 per hour per cluster for versions under standard support, on top of the capacity. A version that's past that period costs $0.60 per hour.
Terms differ from ECS: a task is a Pod, and a server is a Node.
| Node option | How it works |
|---|---|
| EKS Auto Mode | AWS provisions, updates and scales the nodes; it's what AWS recommends going forward |
| Managed node groups | AWS creates and updates the servers, and you choose them |
| Self-managed nodes | You handle everything, for special requirements |
| Fargate | Each Pod runs in isolation without nodes; still available, though Auto Mode is preferred |
For storage, EKS uses CSI drivers to mount EBS, EFS or FSx.
ECS or EKS?
| ECS | EKS | |
|---|---|---|
| Complexity | Fewer concepts, and quick to learn | A big system with a lot to learn |
| Portability | AWS only | The same tools work elsewhere |
| Ecosystem | Close integration with AWS | A huge open-source ecosystem |
| Cost of the service itself | Free | Per hour per cluster |
| Choose it if | You're starting out, and your work is on AWS | Your team knows Kubernetes, or you run across several clouds |
If nothing is pushing you toward Kubernetes, start with ECS on Fargate.
Containers on your own servers
Need the same tools outside AWS, such as in your data center?
| Option | What it does |
|---|---|
| ECS Anywhere | Registers your own servers or virtual machines in an ECS cluster |
| EKS Hybrid Nodes | Adds your own servers as nodes in an EKS cluster |
| EKS Anywhere | Runs Kubernetes clusters on your own infrastructure, for isolated environments |
| EKS Distro | The Kubernetes components behind EKS, for you to run and support yourself |
Hands-on: a service replaces a stopped task
We'll run a public Nginx image on Fargate, with no build needed. From CloudShell, create the cluster and write the recipe. An image from a public registry with no logs doesn't need an execution role:
aws ecs create-cluster --cluster-name series-cluster \
--query cluster.status
cat > task.json <<'EOF'
{
"family": "web",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "256",
"memory": "512",
"containerDefinitions": [{
"name": "web",
"image": "public.ecr.aws/nginx/nginx:latest",
"portMappings": [{"containerPort": 80}],
"essential": true
}]
}
EOF
aws ecs register-task-definition --cli-input-json file://task.json \
--query taskDefinition.family
Prepare the network: the default VPC, a subnet, and a security group that allows port 80 from your CloudShell only:
VPC=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true \
--query "Vpcs[0].VpcId" --output text)
SUBNET=$(aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC \
--query "Subnets[0].SubnetId" --output text)
SG=$(aws ec2 create-security-group --group-name series-web \
--description "Series web task" --vpc-id $VPC \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id $SG \
--protocol tcp --port 80 \
--cidr $(curl -s https://checkip.amazonaws.com)/32
NET="awsvpcConfiguration={subnets=[$SUBNET],securityGroups=[$SG],assignPublicIp=ENABLED}"
Run a single task. If this is your first use of ECS and you get an error about the service-linked role, wait a little and repeat the command:
TASK=$(aws ecs run-task --cluster series-cluster --task-definition web \
--launch-type FARGATE --network-configuration "$NET" \
--query "tasks[0].taskArn" --output text)
aws ecs wait tasks-running --cluster series-cluster --tasks $TASK
Get its address and try it:
ENI=$(aws ecs describe-tasks --cluster series-cluster --tasks $TASK \
--query "tasks[0].attachments[0].details[?name=='networkInterfaceId'].value" \
--output text)
IP=$(aws ec2 describe-network-interfaces --network-interface-ids $ENI \
--query "NetworkInterfaces[0].Association.PublicIp" --output text)
curl -s http://$IP | grep -i "<title>"
You'll see <title>Welcome to nginx!</title>. Your first container is running, with no server you can see. Now stop it, and it stays stopped, because nothing is looking after it:
aws ecs stop-task --cluster series-cluster --task $TASK \
--query task.lastStatus
Create a service that keeps one task running:
aws ecs create-service --cluster series-cluster --service-name web \
--task-definition web --desired-count 1 --launch-type FARGATE \
--network-configuration "$NET" --query service.status
aws ecs wait services-stable --cluster series-cluster --services web
FIRST=$(aws ecs list-tasks --cluster series-cluster --service-name web \
--query "taskArns[0]" --output text)
echo $FIRST
aws ecs stop-task --cluster series-cluster --task $FIRST \
--query task.lastStatus
Wait a minute, then list the tasks:
aws ecs list-tasks --cluster series-cluster --service-name web \
--query taskArns
The ID has changed. The service noticed the task was gone and started another without you lifting a finger.
aws ecs delete-service --cluster series-cluster --service web --force \
--query service.status
aws ecs wait services-inactive --cluster series-cluster --services web
aws ecs delete-cluster --cluster series-cluster --query cluster.status
aws ecs deregister-task-definition --task-definition web:1 \
--query taskDefinition.status
aws ec2 delete-security-group --group-id $SG
Summary
- A container packages the application and its libraries, and shares the host's system, so it's light and fast.
- ECR stores images, and ECS runs them through a task definition, tasks and a service.
- Fargate spares you from managing servers, and it's the best starting point.
- The execution role belongs to ECS, and the task role belongs to your code.
- EKS is for those who need Kubernetes, and ECS Express Mode is the short way for a web application.
Test yourself
Before you move on, try these questions to check you've got this part. Each one is a practical scenario, and the explanation appears once you answer.
Question 1 of 6
A Fargate task starts normally and serves traffic, but when its code writes to DynamoDB it gets AccessDenied. Where should the team add the permission?
Show the answer
Correct answer: D
The task role belongs to your code inside the container. The task's normal start shows the execution role is already doing its job.
- A: ECS uses this one to prepare the task, such as pulling the image and sending logs.
- B: A security group controls network traffic, and this error is about permissions.
- C: Fargate has no servers for you to attach anything to, so instance profiles aren't available.
Review: Two IAM roles, and confusing them is a classic in this part, and Amazon ECS task IAM role in the AWS docs.
Question 2 of 6
A company runs its applications on Kubernetes in its own data center and on another cloud. Its team knows the Kubernetes tools well and wants to keep using them on AWS. What fits?
Show the answer
Correct answer: B
EKS runs the Kubernetes control plane for you, and the team's tools keep working, here and elsewhere.
- A: This is a fine start for most applications, but it's AWS's own system, not Kubernetes.
- C: This builds an ECS web service from an image, and it isn't Kubernetes either.
- D: This runs functions in response to events, and has no Kubernetes in it.
Review: ECS or EKS? in this part, and What is Amazon EKS? in the AWS docs.
Question 3 of 6
A batch job runs in a container every night for about two hours, and nothing needs to run for the rest of the day. What fits at the lowest cost?
Show the answer
Correct answer: C
The schedule starts a task that stops when it's done, and on Fargate you pay only while it runs.
- A: You'd pay for a task 24 hours a day, for two hours of work.
- B: A Lambda run ends at 15 minutes, far short of two hours.
- D: You'd pay for the server around the clock, and have to manage it too.
Review: Not just web services in this part, and Using Amazon EventBridge Scheduler to schedule Amazon ECS tasks in the AWS docs.
Question 4 of 6
Several Fargate tasks in one service need to read and write the same uploaded files, and the files must survive when a task stops. What should the team mount?
Show the answer
Correct answer: A
EFS is a shared file system that tasks can mount on both Fargate and EC2, and the files live outside any one task.
- B: A container's disk disappears with it, and isn't shared with other tasks.
- C: This is a temporary disk on a server, and Fargate gives you no server to attach it to.
- D: This stores container images, not application files.
Review: Storage in this part, and Use Amazon EFS volumes with Amazon ECS in the AWS docs.
Question 5 of 6
An ECS service runs on EC2 servers in an Auto Scaling group. At peak times the service needs more tasks, and those new tasks need servers to land on. Which two features handle this? (Choose two.)
Show the answer
Correct answer: A + E
Service Auto Scaling changes the number of tasks, and a capacity provider adds servers when tasks need them. On EC2 you need both layers.
- B: This lets ECS pull images and send logs, and has nothing to do with scaling.
- C: This looks for vulnerabilities in images.
- D: This spreads traffic across the tasks that exist, and doesn't add any.
Review: Scaling in this part, and Automatically scale your Amazon ECS service and Amazon ECS capacity providers for EC2 workloads in the AWS docs.
Question 6 of 6
A company runs its containers on ECS in AWS. Some must now run on servers in its own factory, and the team wants to keep using the same ECS tools. What fits?
Show the answer
Correct answer: B
ECS Anywhere registers your own servers or virtual machines in an ECS cluster, so the team keeps its tools.
- A: These are Kubernetes components to run and support yourself, and the team uses ECS.
- C: This runs tasks on AWS capacity at a lower price, not on your servers.
- D: This runs in AWS, and no longer accepts new customers.
Review: Containers on your own servers in this part, and Amazon ECS clusters for external instances in the AWS docs.
Containers still run and cost money while waiting. What if your code only ran when there was something to do, and you paid nothing otherwise? In part twenty-one we build an API with Lambda, API Gateway and DynamoDB.