AWS Builder Center

AWS ECS vs EKS: When to Choose What

Everyone says 'it depends' when you ask whether to use ECS or EKS. This post breaks down what it actually depends on, covering control plane overhead, Fargate trade-offs, networking models, IAM vs RBAC, and the concrete criteria that should drive the decision.

When I started going deeper into cloud infrastructure, this question kept coming up. In docs I was reading, in YouTube talks, in architecture diagrams from open-source projects: "Should we use ECS or EKS?"
And every answer I found said the same thing: "It depends."
That is technically true. But it is also completely useless if you do not know what it depends on. So I spent a while going down this rabbit hole, and this post is me writing up what I found. Not the definitive guide, just the things that actually helped me understand the difference.

A Quick Note Before We Start

In the HIS project, I ran a full Kubernetes setup locally: multi-node cluster on Kind, HashiCorp Vault for secret management, NetworkPolicies for micro-segmentation, anti-affinity rules, PodDisruptionBudgets, and six live chaos tests with Chaos Mesh. That experience gave me a very concrete sense of what Kubernetes actually costs you operationally, and made me genuinely appreciate the cases where that cost is not worth paying.
That is what shaped how I think about this topic.

1. What Are We Even Comparing?

Both ECS and EKS are container orchestrators. Their job is the same: take your Docker images and keep them running at scale. The difference is in how they approach that.
ECS (Elastic Container Service) is AWS's own orchestration engine. AWS built it, AWS runs it. You work with concepts like Tasks, Services, and Task Definitions. There is no control plane to manage; it is entirely invisible to you.
EKS (Elastic Kubernetes Service) is managed Kubernetes. Kubernetes is an open-source orchestrator originally built at Google. EKS handles running the control plane, but you are still working with Kubernetes: Pods, Deployments, Services, Ingress, RBAC, and the full K8s API surface.
The way I think about it: ECS is AWS's opinionated answer to container orchestration. EKS is the open-source industry standard, with AWS managing the hard parts.

2. The Control Plane: The Invisible vs The Visible

This is the difference that took me the longest to properly understand.

ECS: The Control Plane Does Not Exist For You

In ECS, there is no control plane you interact with. You define a Task Definition (basically your container blueprint) and tell ECS to run it as a Service. AWS decides how to schedule it, how to restart it, how to distribute it. You never kubectl exec into a scheduler. You never tune etcd. It just works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// A minimal ECS Task Definition
{
"family": "payment-service",
"containerDefinitions": [
{
"name": "payment-service",
"image": "123456789.dkr.ecr.eu-west-1.amazonaws.com/payment-service:latest",
"cpu": 256,
"memory": 512,
"portMappings": [
{ "containerPort": 8080, "protocol": "tcp" }
]
}
],
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "256",
"memory": "512"
}
You write this, register it, and ECS handles the rest.

EKS: The Control Plane Is Something You Need To Understand

In EKS, the control plane (API Server, etcd, Controller Manager, Scheduler) is managed by AWS, but you still interact with it constantly through kubectl. You write Pods, Deployments, Services. You need to know how the scheduler picks nodes, what taints and tolerations do, how resource requests affect scheduling.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# A minimal EKS Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 3
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: payment-service
image: 123456789.dkr.ecr.eu-west-1.amazonaws.com/payment-service:latest
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "1Gi"
ports:
- containerPort: 8080
More verbose. More powerful. More to learn.
One thing I did not realise at first: EKS charges ~$0.10/hour per cluster just for the control plane, even if you run zero workloads. ECS has no equivalent cost. For small projects or dev environments, this adds up.

3. The Compute Layer: Fargate Changes Everything

Something that confused me early on: ECS and EKS are orchestrators, not compute. The actual machines running your containers are separate.
Both can run on:
  • EC2 instances: You manage the nodes, patching, scaling, and AMIs
  • AWS Fargate: Serverless. You define CPU and memory, AWS runs the container. No nodes to think about.
But there is an important asymmetry here: Fargate works much more naturally with ECS.
With ECS + Fargate, the abstraction is genuinely clean. You write a Task Definition, set CPU and memory, and the concept of "a server" kind of disappears. Your team focuses on the application, not on node groups, AMIs, or capacity planning.
With EKS + Fargate, things get messier. Fargate on EKS uses Fargate Profiles to match Pods to serverless compute via namespace and label selectors. It works, but with real constraints: no DaemonSets, no privileged containers, no hostPath volumes, no GPU support. In HIS, Chaos Mesh's chaos-daemon runs as a DaemonSet on every node to inject failures at the kernel level, and that alone would have been a blocker on EKS + Fargate.

4. Networking: VPC Native vs The CNI World

ECS: awsvpc Mode

ECS tasks in awsvpc mode get their own Elastic Network Interface (ENI). Each task has its own private IP inside your VPC. Security Groups apply directly to the task, exactly like they do for EC2 instances. The model is familiar and integrates naturally with ALB, NLB, PrivateLink, and Service Connect.

EKS: The CNI Layer

Kubernetes has its own networking model. Pods get their own IPs, but how they get those IPs depends on the CNI plugin. AWS provides the Amazon VPC CNI, which assigns real VPC IPs to Pods. No overlay network, which is good.
But there are complications I did not expect:
  • Each EC2 instance can only hold a limited number of ENIs, so there is a hard ceiling on how many Pods it can run
  • You need to understand Kubernetes Services (ClusterIP, NodePort, LoadBalancer) and how kube-proxy manages traffic rules
  • Ingress requires an Ingress Controller as a separate component you install and maintain
1
2
3
# ENI limits per instance type (this caught me off guard)
m5.large: max 3 ENIs × 10 IPs = 30 Pods
m5.xlarge: max 4 ENIs × 15 IPs = 60 Pods
If you are running many small services on few nodes, ENI limits become a real planning constraint. I only learned this by reading the AWS docs carefully. It is not something that comes up in the "getting started" guides.

5. IAM and Security: Task Role vs RBAC + IRSA

ECS: IAM Task Roles

In ECS, you attach an IAM Role directly to the Task Definition. The container picks up that role's credentials through the metadata endpoint, which is conceptually identical to an EC2 Instance Profile.
1
2
// In your Task Definition
"taskRoleArn": "arn:aws:iam::123456789:role/payment-service-task-role"
If your service needs to write to S3 and publish to SQS, you attach exactly those permissions to its task role. One system, one mental model.

EKS: IRSA (IAM Roles for Service Accounts)

In EKS, there is no Task Role concept. Pods get AWS credentials through IRSA (IAM Roles for Service Accounts):
  1. You create a Kubernetes Service Account
  2. You annotate it with an IAM Role ARN
  3. EKS's OIDC provider issues a signed JWT to the Pod
  4. The Pod exchanges that JWT with AWS STS for temporary credentials
1
2
3
4
5
6
apiVersion: v1
kind: ServiceAccount
metadata:
name: payment-service
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/payment-service-role
IRSA works well, but now you have two permission systems running in parallel: Kubernetes RBAC (who can do what inside the cluster) and AWS IAM (who can do what in AWS). I have read enough incident reports to know that forgetting to configure RBAC after setting up IRSA is a real trap. Your Pod might have full AWS permissions but cannot even read a ConfigMap because the K8s RBAC policy is missing. Two systems, two potential failure points.

6. Observability: What Changes?

With ECS, the observability stack lives in the AWS ecosystem. CloudWatch Container Insights, ECS Service Connect metrics, X-Ray for tracing, and VPC Flow Logs all work together with minimal configuration.
With EKS, the typical production stack looks like:
  • Prometheus + Grafana for metrics
  • Fluent Bit as a DaemonSet for log shipping
  • OpenTelemetry Collector for traces
  • kube-state-metrics for cluster-level metrics
These tools are genuinely more powerful and completely portable. But in HIS, getting this observability stack to a reasonable state was a significant piece of infrastructure work on its own, and that was before I had written a single line of application logic.

7. What I Would Ask Before Choosing

After going through all of this, the question I keep coming back to is not "which one is better" but "which one fits the context."
Here is how I think about it now:

ECS probably makes more sense when:

  • The team is small or does not have existing Kubernetes experience. Getting productive on ECS does not require a dedicated platform engineer.
  • You are fully committed to AWS and have no plans to go multi-cloud. ECS's tight AWS integration stops being a limitation and starts being a feature.
  • You want the cleanest possible Fargate experience. No node management, no ENI limits, no DaemonSet workarounds.
  • The workload is relatively straightforward: batch jobs, a handful of microservices, internal tools.
  • Keeping infrastructure costs simple matters. No control plane overhead.

EKS probably makes more sense when:

  • The team already knows Kubernetes. K8s knowledge is portable across clouds; forcing Kubernetes engineers into ECS means asking them to learn a proprietary system.
  • You need the open-source ecosystem. Helm, Argo CD, Istio, Kyverno, KEDA, Crossplane; none of this exists for ECS. If you need GitOps, policy enforcement, or a service mesh, this matters.
  • The architecture genuinely needs K8s primitives: CRDs, Operators, advanced scheduling, topology spread constraints, Horizontal Pod Autoscaler with custom metrics.
  • You need to keep the option open to run workloads somewhere other than AWS.
  • The platform is expected to grow substantially. ECS will eventually hit ceilings that EKS does not have.

8. Side by Side

ECSEKS
Learning curveLowHigh
Control plane cost$0~$0.10/hour
Fargate experienceNative & cleanWorks, with constraints
AWS integrationTightGood, via add-ons
Multi-cloud portabilityNoneFull
EcosystemAWS-onlyMassive open-source
Operational overheadLowerHigher
Customisation ceilingLimitedVirtually unlimited

Conclusion

The thing that surprised me most going through all of this: ECS is not a "beginner" tool. It is a fully capable orchestrator that is the right answer for a lot of production workloads. I think the instinct to jump straight to EKS because it feels more serious is a mistake, and I have seen it described as a trap in more than a few architecture discussions.
The question is really just: does Kubernetes's flexibility justify its operational overhead in your specific situation?
In HIS, it did. NetworkPolicies for micro-segmentation across nine services, anti-affinity rules to spread replicas across nodes, PodDisruptionBudgets for controlled chaos testing with Chaos Mesh, HashiCorp Vault wired up through External Secrets Operator. Every one of those primitives was there for a real reason. In a simpler project, all of that machinery would have been infrastructure for its own sake.
That is the version of "it depends" that is actually useful.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article