Containers on AWS: An Overview
A container is a lightweight package that holds your application plus everything it needs to run (code, runtime, libraries), so it behaves the same on your laptop and in the cloud. Docker is the most common tool for building containers. AWS does not have one “container service” — it has a small family of services that each do a different job, and the names sound similar enough to be confusing. This page is a map: it shows what each service is for and, most importantly, how to make the two real decisions that trip up almost everyone.
The registry / orchestrator / compute split
The single most useful idea here is that running containers on AWS involves three separate layers. Once you see them as separate, the service names stop blurring together.
| Layer | Question it answers | AWS services |
|---|---|---|
| Registry | Where do my built container images live? | ECR (Elastic Container Registry) |
| Orchestrator | What schedules, places, scales, and restarts my containers? | ECS (Elastic Container Service) or EKS (Elastic Kubernetes Service) |
| Compute | What physical capacity actually runs the containers? | EC2 (Elastic Compute Cloud) instances or Fargate (serverless) |
You almost always use all three layers together: you push an image to a registry, an orchestrator decides where to run it, and that container lands on some compute. App Runner is the exception — it bundles all three into one managed service, which we cover below.
The gotcha that loses beginners: The first decision is not “which container service?” It is two independent decisions — which orchestrator (ECS vs EKS) and which compute (EC2 vs Fargate). People treat “ECS”, “EKS”, and “Fargate” as competing options on one list and get stuck. They are not on the same list. You pick one orchestrator and one compute mode. “ECS on Fargate” and “EKS on EC2” are both valid, common combinations.
ECR — the registry
ECR (Elastic Container Registry) is AWS’s private Docker image registry. It is the AWS-native equivalent of Docker Hub. You build an image locally (or in CI), push it to ECR, and your orchestrator pulls it from there to run.
When to use it: Almost always, if you run containers on AWS. It is private by default, integrates with IAM (Identity and Access Management) for access control, and scans images for known vulnerabilities. When NOT to: if your images are public and you are fine with a public registry’s rate limits, you can pull straight from Docker Hub — but most teams want a private, in-account registry.
Create a repository and push an image. First, create it:
aws ecr create-repository --repository-name my-app --region us-east-1
Output:
{
"repository": {
"repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/my-app",
"registryId": "111122223333",
"repositoryName": "my-app",
"repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app"
}
}
Then log in, tag, and push:
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
docker tag my-app:latest 111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
Cost note: ECR charges about $0.10 per GB-month of stored images, plus normal data-transfer fees. Set a lifecycle policy to delete old image tags so storage does not creep up over the years.
ECS vs EKS — the orchestrator decision
An orchestrator is the “brain” that keeps your containers running: it places them on capacity, restarts crashed ones, scales the count up and down, and rolls out new versions.
- ECS (Elastic Container Service) is AWS’s own orchestrator. It is simpler, deeply integrated with the rest of AWS, and has no control-plane fee. You describe what to run in a task definition and ECS handles the rest.
- EKS (Elastic Kubernetes Service) is managed Kubernetes — the open-source orchestrator that the wider industry standardizes on. AWS runs the Kubernetes control plane for you. It is more powerful and portable, but more complex, and the control plane costs about $0.10/hour (roughly $73/month) per cluster.
| ECS | EKS | |
|---|---|---|
| What it is | AWS-native orchestrator | Managed Kubernetes |
| Learning curve | Lower — AWS concepts only | Higher — full Kubernetes |
| Portability | AWS-only | Runs anywhere Kubernetes runs |
| Control-plane cost | Free | ~$0.10/hour per cluster |
| Best for | Teams who want simple, AWS-only container hosting | Teams already invested in Kubernetes or needing multi-cloud |
When to use ECS: you want the shortest path to running containers on AWS and have no Kubernetes requirement. When to use EKS: your team already knows Kubernetes, you need its ecosystem (Helm, operators), or you want portability across clouds. When NOT to use EKS: for a small, AWS-only app — you would pay the control-plane fee and the complexity tax for nothing.
EC2 vs Fargate — the compute decision
Independently of the orchestrator, you choose what supplies the raw compute. Both ECS and EKS support both options.
- EC2 launch type: you run and manage a pool of EC2 virtual machines (instances like
i-0a1b2c3d4e5f), and containers pack onto them. You control the instance type, can use Spot or GPU instances, and pay for the whole machine whether it is full or not. - Fargate: serverless compute. You never see or patch a server — you just declare CPU and memory per task, and AWS runs it. You pay per task for the exact CPU/memory you requested.
When to use Fargate: you want zero server management and bursty or unpredictable workloads. When to use EC2: you have steady, high-density workloads where packing many containers onto reserved instances is cheaper, or you need GPUs or special instance types Fargate does not offer.
App Runner — the all-in-one option
App Runner is a fully managed service that hides all three layers. You point it at a container image in ECR (or a source repo) and it builds, deploys, load-balances, scales to zero, and gives you an HTTPS URL — no orchestrator or compute choices to make.
aws apprunner create-service \
--service-name my-web-app \
--source-configuration '{"ImageRepository":{"ImageIdentifier":"111122223333.dkr.ecr.us-east-1.amazonaws.com/my-app:latest","ImageRepositoryType":"ECR"}}'
When to use it: a single web service or API where you want the least possible operations work. When NOT to: complex multi-service systems, batch jobs, or anything needing fine-grained networking control — reach for ECS or EKS instead.
Putting it together (console flow)
To stand up a typical containerized web app on ECS + Fargate from the AWS Management Console:
- Open the ECR console and click Create repository; push your image to it.
- Open the ECS console and click Create cluster (choose Networking only / Fargate).
- Create a Task definition, choosing the Fargate launch type and pointing the container at your ECR image URI.
- Create a Service from that task definition and set the desired task count (e.g. 2).
- Attach an Application Load Balancer so traffic reaches your tasks on a public URL.
Best Practices
- Always separate the three layers in your head: registry (ECR), orchestrator (ECS/EKS), compute (EC2/Fargate).
- Default to ECS on Fargate for new, AWS-only workloads — it is the lowest-effort, no-server starting point.
- Only choose EKS when you have a real Kubernetes need; otherwise you pay the control-plane fee and complexity for nothing.
- Use ECR with image scanning enabled and a lifecycle policy to purge old, vulnerable image tags.
- Pick EC2 launch type only for steady, dense, or specialized (GPU/Spot) workloads where it beats Fargate on cost.
- Reach for App Runner when a single service just needs a URL and you want to skip orchestration entirely.