avatar Post

Do You Really Need Kubernetes? Lambda vs ECS vs EKS on AWS

Kubernetes on AWS

What Kubernetes is and what Amazon EKS brings, and how to choose between Lambda, ECS, EKS or EC2 on AWS by asking for a concrete requirement before taking on the complexity of Kubernetes.

2 articles

Complete
Do You Really Need Kubernetes? Lambda vs ECS vs EKS on AWS

In Part 1 of this series I explained why Kubernetes seems to me a very powerful platform and also a very complex one. Now comes the question that weighs a lot more for me: whether I really need it for this application. Here I don’t compare services one by one. I walk through the order in which I ask myself questions and the requirements I look for before saying yes to Amazon EKS.

My bias on AWS is well known: if I can solve the problem cleanly with serverless, I usually start there. Not because AWS Lambda is always better or because containers are bad, but because every layer of infrastructure I can avoid is a layer I don’t have to patch, scale, upgrade, monitor or explain later.

Serverless doesn’t fit everything either. So instead of starting by picking a technology, I start by asking what the workload actually needs.

Compute first, and only if it’s needed

Imagine a React SPA. After the build we have JavaScript, HTML, CSS and static images. We could package it in a container and deploy it on ECS or EKS, but the right question is a different one: why do I need a server to serve static files? In many cases this is enough:

flowchart LR
    U[User] --> CF[CloudFront]
    CF --> S3[S3]

No Pods, no Tasks, no EC2. That gives me my first rule: don’t choose the type of compute until you’ve confirmed you need compute.

If I do need it, I try to start with serverless. When the application fits an event-driven model or independent requests, AWS Lambda is usually my first option, alongside Amazon API Gateway, Amazon DynamoDB or Amazon S3:

flowchart LR
    A[API Gateway] --> L[Lambda]
    L --> D[DynamoDB]

    S[S3] --> E[Event]
    E --> L2[Lambda]

I don’t have to decide how many servers I need, where to run them or how they scale. AWS takes care of the infrastructure and I focus on the application logic.

That is what I’m after when I talk about serverless: not that servers don’t exist, but that they are not part of my daily operating model.

Lambda usually fits especially well when:

  • the work is event-driven;
  • each execution can be independent;
  • the application tolerates Lambda’s execution model;
  • I want to scale per invocation;
  • I want to minimize the infrastructure I have to operate.

When that stops fitting, then I look at containers.

Having containers doesn’t mean needing Kubernetes

This is probably the most important idea in the article. Say I need a long-running process, an application that already comes containerized or a runtime that doesn’t fit well in Lambda. Fine: I need containers. But from there, there are two very different paths:

flowchart TB
    C[Container]
    C --> ECS[ECS<br/>AWS-native orchestration]
    C --> EKS[EKS<br/>Kubernetes]

Amazon ECS lets me run and scale containers with an AWS-native model; Amazon EKS lets me do it with Kubernetes. Both can run microservices, balance traffic, scale applications and deploy across several Availability Zones. So the question is not whether I have containers, but what I need from Kubernetes that a plain container orchestrator doesn’t give me.

How do I know if I need Kubernetes

A decision tree that just says Do you need Kubernetes? Yes: EKS; no: ECS isn’t worth much: if we are asking the question it’s because we don’t know the answer yet. What I look for are explicit Kubernetes requirements, and these are the ones I consider valid:

  • A Kubernetes platform already exists in the organization. If a platform team already provides GitOps, observability, policies, security, Helm charts, Operators and a standard way to deploy, Kubernetes is already part of the operating model and adding another workload can be straightforward.
  • I need something specific to the Kubernetes ecosystem. Some products and platforms are designed around Helm, CRDs or Operators, and if Kubernetes is a natural part of how they are installed or operated, EKS makes a lot more sense.
  • I need real Kubernetes portability. There may be a genuine requirement to run the same workloads across AWS, on-premises or other Kubernetes environments.
  • I’m building a platform for many teams. Kubernetes’ complexity pays off much better when a common platform serves dozens of teams and workloads than when you’re deploying three microservices.
  • I need advanced scheduling or extensibility. GPUs, special topologies, Operators, custom resources or automation built on the Kubernetes API are all perfectly valid reasons.

The important word in portability is “real”. I wouldn’t take on all of Kubernetes’ complexity for a hypothetical “maybe someday we’ll change cloud”.

If I can’t find anything like this, Amazon ECS deserves to be evaluated before EKS.

What doesn’t mean you need Kubernetes

I wouldn’t choose EKS just because:

  • I have microservices or use Docker;
  • I have many APIs;
  • I need autoscaling or high availability;
  • I need rolling deployments, service discovery or a load balancer.

Kubernetes can do all of that, but so can ECS, with a much smaller operating model.

That Kubernetes can solve a problem doesn’t mean Kubernetes is necessary to solve it.

The decision tree, Fargate and EC2

With all this, this is roughly how I think about it:

Choosing the right compute option on AWS: static hosting, Lambda, ECS, EKS or EC2 The idea is not to memorize a perfect tree, but to start with the simplest option and ask for a concrete reason before taking on more infrastructure and more operational load.

flowchart TB
    A{Do I need compute?}

    A -->|No| STATIC[Static hosting<br/>S3 + CloudFront / Amplify]
    A -->|Yes| B{Does it fit as<br/>event-driven execution<br/>or a function?}

    B -->|Yes| L[Lambda]
    B -->|No| C{Do I need a persistent<br/>process or container?}

    C -->|Yes| D{Do I have a specific<br/>Kubernetes requirement?}
    D -->|Yes| EKS[EKS]
    D -->|No| ECS[ECS]

    C -->|No / I need VM control| EC2[EC2]

It is not a universal algorithm and there will always be exceptions. What I like about this tree is that every step towards more infrastructure has to be justified by a requirement.

AWS Fargate often shows up in these comparisons as if it were another alternative to ECS or EKS, but it answers a different question.

ECS and EKS answer how I orchestrate my containers. Fargate answers who manages the infrastructure they run on.

You can run ECS workloads on Fargate without managing the underlying EC2 instances, and Fargate also integrates with EKS for certain Pods. The ECS + Fargate combination seems especially interesting to me when I need containers but want to keep a philosophy close to serverless: running the workload without directly managing hosts.

AWS also offers ECS Express Mode, which simplifies certain containerized web deployments even further by automatically configuring a good part of Fargate, networking, load balancing and autoscaling.

Amazon EC2 still makes sense when I need an actual machine. For example, for:

  • operating system control;
  • legacy software that is hard to adapt;
  • host-specific configuration;
  • appliances;
  • very specific network or storage requirements.

EC2 gives you a lot of control and also hands back a lot of responsibilities.

That’s fine if I need that control. What I try to avoid is taking it on when it brings me nothing.

Quick comparison

 LambdaECSEKSEC2
ModelFunctionsAWS containersKubernetesVirtual machines
Infrastructure to manageVery littleLow / mediumMedium / highHigh
ControlLowMediumHighVery high
Operational complexityLowLow / mediumHighHigh
KubernetesNoNoYesOnly if you install it
My typical caseAPIs and eventsContainer with no Kubernetes needReal Kubernetes requirementReal host/OS need

I don’t read this table as a scale where more control means better. It’s usually the opposite: I want to take on only the control I need.

A few examples help to see it:

  • A static React frontend (React -> build -> S3 -> CloudFront) needs no compute.
  • Processing a file uploaded to S3 (S3 -> event -> Lambda -> result) fits Lambda naturally.
  • A containerized API with no Kubernetes requirements, with several Docker microservices, autoscaling and load balancing, doesn’t force me into Kubernetes: ECS + Fargate would be one of the first options to evaluate.
  • A common platform for dozens of teams based on GitOps, Helm and Operators changes the picture completely. Kubernetes is no longer just where I run the container, it is the platform’s API, and EKS makes much more sense.
  • A legacy application that needs full control of the host is probably EC2. I wouldn’t try to turn it into serverless or Kubernetes just because that’s more modern.

A real architecture doesn’t have to pick just one

A platform can perfectly well end up like this:

flowchart LR
    U[User] --> CF[CloudFront]
    CF --> S3[S3 - frontend]
    CF --> API[API Gateway]
    API --> L[Lambda]
    L --> DB[(DynamoDB)]

    L --> Q[SQS]
    Q --> ECS[ECS workload]

    EKS[Specialized EKS workload]

And that’s fine. One of AWS’s strengths is being able to choose different abstractions for different workloads, and there is no prize for getting everything to run on Kubernetes.

My final rule is to always start with the solution that leaves the least infrastructure for me to operate:

  • If I can serve it statically, I add no compute.
  • If it fits Lambda, I usually prefer serverless.
  • If I need containers, I evaluate ECS.
  • If I truly have Kubernetes requirements, EKS can be an excellent platform.

An architecture shouldn’t start with “I want to use EKS”, but end up at EKS once the requirements have justified it.

Kubernetes is very powerful, and that is precisely why I don’t think we should use it for everything.

References

This post is licensed under CC BY 4.0 by the author.