Module 7: Eks Specifics For Production

4. Node autoscaling: Karpenter vs Cluster Autoscaler

Description

In Module 3, lesson 7, you installed metrics-server, resolved kind's self-signed certificate friction, and watched a HorizontalPodAutoscaler really react to real load, raising and lowering andes-cargo-status-api's replica count. That mechanism worked exactly as expected, executed, with literal evidence from kubectl get hpa -w. But there's a question that module deliberately left unanswered, because kind has no way to answer it: what happens when the HPA wants to create more Pods, but there's no free space left on any existing node? In kind, the answer is "those Pods stay Pending forever" — there's no mechanism to add a fourth Docker container as a new node. In EKS, that question gets answered by a component completely different from the HPA, with a completely different job: node autoscaling.

Connection to the module

This lesson requires you to have fresh the distinction you already built in Module 3: a HorizontalPodAutoscaler watches Pod metrics (CPU, memory, or other custom ones) and decides how many replicas there should be — but it never creates or destroys a node, because that's not its job. This lesson presents the component that does, and why in 2026 AWS's default answer to that question has its own name: Karpenter.


The exact distinction: what the HPA scales, what this scales

        TWO DIFFERENT AUTOSCALING LOOPS, TWO DIFFERENT QUESTIONS

  HorizontalPodAutoscaler (Module 3, EXECUTED on kind)
  ──────────────────────────────────────────────────────
  Question: "how many REPLICAS of this Deployment do I
             need for the current load?"
  Acts on: the Deployment's spec.replicas
  Never touches: nodes — it assumes they already exist and have room

           ┌─────────────────────────────────────┐
           │  Node A       Node B      Node C      │
           │  [Pod] [Pod]  [Pod]       [Pod]        │  ◀── HPA raises/lowers
           │                                         │      HOW MANY Pods
           └─────────────────────────────────────┘      there are, on nodes
                                                            that already exist

  Karpenter / Cluster Autoscaler (this module, representative on EKS)
  ─────────────────────────────────────────────────────────────────
  Question: "is any Pod Pending because NO current node
             has room? Is any node sitting empty?"
  Acts on: the cluster's number of NODES (EC2 instances)
  Never decides: how many replicas a Deployment should have

           ┌───────┐  ┌───────┐  ┌───────┐  ┌───────┐
           │Node A │  │Node B │  │Node C │  │Node D │  ◀── Karpenter
           │ full  │  │ full  │  │ full  │  │ NEW,  │      launches a
           └───────┘  └───────┘  └───────┘  │created│      new node
                                              │now    │      when there's
                                              └───────┘      no room

Neither mechanism replaces the other — they need each other, in a cascade: the HPA decides more replicas are needed; if existing nodes have no room to schedule them, those replicas stay Pending; that is the signal that triggers Karpenter (or Cluster Autoscaler) to create a new node where the scheduler can actually place them. Without node autoscaling, an HPA asking for more replicas than fit in your current capacity keeps asking for something that's never going to arrive — exactly what would have happened if Module 3 had pushed load high enough on kind: your laptop's nodes have a real physical limit no autoscaler can solve, because there's no cloud behind it to ask for more.


Karpenter: AWS's default in 2026

Karpenter is a high-performance, open-source cluster autoscaler, designed specifically to launch compute just-in-time: instead of working with a predefined instance group (as the older approach does, see below), Karpenter directly watches unscheduled Pods and decides, on the spot, the exact instance type and size to launch so they fit — with no human needing to have predefined ahead of time "this node group uses t3.medium."

AWS's official documentation confirms that EKS Auto Mode, the most recent form of simplified compute administration for EKS, builds directly on Karpenter — this is the citation that anchors this lesson, verified against docs.aws.amazon.com/eks:

"Amazon EKS Auto Mode automatically scales cluster compute resources. If a pod can't fit onto existing nodes, EKS Auto Mode creates a new one. EKS Auto Mode also consolidates workloads and deletes nodes. EKS Auto Mode builds upon Karpenter."

That last sentence — "EKS Auto Mode builds upon Karpenter" — is why this lesson calls Karpenter "AWS's recommended default in 2026," with no exaggeration: it's not that AWS tolerates it as a third-party alternative, it's that the newest, simplified way AWS offers to administer EKS compute uses Karpenter underneath, though wrapped in an additional managed layer.

AWS's own documentation is equally precise about the support model when you use Karpenter directly (bypassing EKS Auto Mode):

"Karpenter is open-source software which AWS customers are responsible for installing, configuring, and managing in their Kubernetes clusters. AWS provides technical support when Karpenter is run unmodified using a compatible version in Amazon EKS clusters. There is no AWS Service Level Agreement (SLA) for Karpenter."

This distinction matters: EKS Auto Mode (Karpenter, AWS-administered, with AWS support over the managed layer) isn't the same as self-managed Karpenter (you install it, you keep it updated, AWS helps you technically but with no formal SLA over Karpenter itself). Both use the same engine underneath — the difference is, again, who administers the lifecycle.

How Karpenter decides, in one sentence with a sourced citation: "Karpenter launches right-sized compute resources (for example, Amazon EC2 instances) in response to changing application load in under a minute" — it watches the exact compute, storage, acceleration (GPU), and scheduling requirements of unscheduled Pods, and launches the best-fitting EC2 instance, instead of forcing everything into a fixed, predefined instance size.

With a Karpenter NodePool (representative) — the configuration unit you use to tell Karpenter which instance types to consider:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: andes-cargo-general
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["t", "m"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: andes-cargo-nodeclass
  limits:
    cpu: 100

Cluster Autoscaler: the older approach, still current by contrast

The Kubernetes Cluster Autoscaler is the older of the two mechanisms, and AWS still documents it as one of the "Additional Solutions" supported alongside Karpenter — it isn't deprecated, but the official documentation's own structure positions it after Karpenter, not as the first default. Its underlying difference from Karpenter, in AWS's exact words:

"The Kubernetes Cluster Autoscaler automatically adjusts the number of nodes in your cluster when pods fail or are rescheduled onto other nodes. The Cluster Autoscaler uses Auto Scaling groups."

The key phrase: "uses Auto Scaling groups." Cluster Autoscaler doesn't launch instances made-to-measure, like Karpenter does — it works over Auto Scaling groups that already exist, with instance sizes already fixed ahead of time, and its only lever is raising or lowering those groups' desiredCapacity. If you need an instance type no existing Auto Scaling Group covers, Cluster Autoscaler can't improvise a new one — Karpenter, on the other hand, evaluates each unscheduled Pod's exact requirement and chooses from a much broader catalog of instance types, with no predefined group needed for every possible combination.

When does a team choose Cluster Autoscaler in 2026, knowing Karpenter is the recommended default? The case AWS and the community cite most consistently is multi-cloud: Cluster Autoscaler has implementations for AWS, GCP, Azure, and other providers with a common API, while Karpenter, in its native AWS form, is built specifically for EC2's model — a team administering Kubernetes clusters on more than one cloud provider, looking for a single consistent operating mechanism across all of them, may prefer Cluster Autoscaler for that portability, even giving up Karpenter's speed and precision within AWS.


Contrast table

KarpenterCluster Autoscaler
How it decides what to launchDirectly evaluates the unscheduled Pod, chooses the optimal instance type on the spotRaises/lowers an Auto Scaling Group's desiredCapacity with size already fixed
Needs a predefined instance groupNoYes — works over existing Auto Scaling Groups
Documented reaction speed"in under a minute"Depends on the Auto Scaling Group's own reaction time
AWS supportNo formal SLA if self-managed; with AWS support if run via EKS Auto ModeSupported as a documented alternative, without being the default
Multi-cloudNo — native to AWS/EC2Yes — implementations for multiple providers
Relationship with EKS Auto ModeIs the foundation ("builds upon Karpenter")Not part of EKS Auto Mode

Common mistakes

Thinking Karpenter replaces the HorizontalPodAutoscaler, and that the HPA is no longer needed in a real EKS cluster (layer confusion). What happens: someone, learning about Karpenter, assumes they no longer need Module 3's HorizontalPodAutoscaler in production. How to spot it: if your migration plan (this module's project, lesson 8) removes hpa.yaml from the repository instead of keeping it. How to fix it: they're complementary mechanisms, not substitutes — the HPA still decides how many replicas of andes-cargo-status-api you need; Karpenter only comes into play when those replicas don't fit in current compute. Without the HPA, Karpenter would have no "I need more Pods" signal to react to.

Assuming Karpenter and EKS Auto Mode are exact synonyms (vocabulary). What happens: someone uses "Karpenter" and "EKS Auto Mode" interchangeably, as if they were the same product with two names. How to spot it: if you describe EKS Auto Mode as "another name for Karpenter" with no nuance. How to fix it: this lesson's exact citation says EKS Auto Mode "builds upon Karpenter" — it builds on it, it isn't identical to it. EKS Auto Mode adds an AWS-managed layer on top of Karpenter's engine (including, for example, AMI management and updates self-managed Karpenter doesn't include on its own). You can use Karpenter directly, bypassing EKS Auto Mode, and it's still Karpenter — just without that additional managed layer.

Choosing Cluster Autoscaler "because it's the most familiar one," without evaluating whether the multi-cloud case applies (decision criterion). What happens: someone, familiar with Cluster Autoscaler from previous projects, picks it out of habit on a new EKS cluster without evaluating whether Karpenter would suit it better. How to spot it: if your justification for choosing Cluster Autoscaler mentions no real cross-cloud portability requirement. How to fix it: given that AWS itself documents Karpenter as the foundation of its newest solution (EKS Auto Mode) and as the recommended default, the right question isn't "which one do I know?" but "does this cluster need real multi-cloud portability?" — if the answer is no, Karpenter is the choice this lesson's evidence backs.


Exercises

Exercise 1 — Trace the complete flow, from load to new node. In your own words, describe the complete chain of events, in order, from andes-cargo-status-api's traffic rising to a new EC2 node appearing on the cluster — naming which component does each step.

See solution

(1) andes-cargo-status-api's Pods' real CPU rises, measured by metrics-server. (2) The HorizontalPodAutoscaler (Module 3) detects utilization exceeds the configured target and increases the Deployment's spec.replicas. (3) kube-scheduler tries to schedule the new Pods, but no existing node has enough free room — those Pods stay Pending. (4) Karpenter (or Cluster Autoscaler) detects the Pending Pods with no compatible node, and launches a new EC2 instance sized for those Pods' exact requirement. (5) The scheduler schedules the Pods, now successfully, on the newly created node. If your answer identified all four components in that order (metrics-server → HPA → scheduler → Karpenter/Cluster Autoscaler), you captured the complete chain.

Exercise 2 — Explain "builds upon Karpenter" without using the word "builds." A colleague asks you what exactly "EKS Auto Mode builds upon Karpenter" means. Explain it to them in one sentence, without using the word "builds" or "build."

See solution

A complete explanation sounds, roughly, like this: "The engine that decides which instance to launch and when, inside EKS Auto Mode, is Karpenter — AWS simply adds a managed layer on top (AMI management, updates, formal support) so you don't have to install or maintain it yourself." If your answer distinguished "the decision engine" from "the managed layer wrapping it," you captured the real relationship between the two.

Exercise 3 — Predict the outcome if Karpenter needs an instance type a Cluster Autoscaler Auto Scaling Group doesn't cover. If an unscheduled Pod requires a GPU instance, and the cluster uses Cluster Autoscaler with Auto Scaling Groups configured only for t3/m5 instances with no GPU, what would happen? Compare it with what Karpenter would do in the same scenario.

See solution

With Cluster Autoscaler: the Pod would stay Pending indefinitely — Cluster Autoscaler can only raise the desiredCapacity of Auto Scaling Groups that already exist, and if none of them offer GPU instances, it has no way to create a new group on its own; someone would have to manually create a new Auto Scaling Group with the correct instance type. With Karpenter: by directly evaluating the unscheduled Pod's requirements (including the GPU need, one of the criteria AWS's documentation explicitly mentions Karpenter considers), it would launch a compatible GPU instance with no one needing to have predefined that instance type ahead of time — the exact difference between "working over predefined groups" and "evaluating the exact requirement on the spot" this lesson explained.


Summary and next step

This lesson distinguished, with evidence and a sourced citation, two autoscaling loops solving completely different questions: Module 3's HorizontalPodAutoscaler (executed on kind) decides how many replicas of a Deployment are needed, over nodes that already exist; Karpenter and Cluster Autoscaler decide how many nodes are needed, reacting to Pods left Pending for lack of capacity. You confirmed, with the exact citation from docs.aws.amazon.com/eks, that EKS Auto Mode "builds upon Karpenter" — the engine behind the newest, simplified way of administering EKS compute — and contrasted that against Cluster Autoscaler, the older approach, based on predefined Auto Scaling Groups, still current mostly for multi-cloud cases.

Before moving on you should be able to: explain, without confusing them, what the HPA scales and what Karpenter/Cluster Autoscaler scales; cite the exact relationship between EKS Auto Mode and Karpenter; and justify when a real team would choose Cluster Autoscaler over Karpenter in 2026.

Next lesson: IRSA and its successor, EKS Pod Identity. There you're going to see the same OIDC pattern you already know from cicd-and-gitops-on-aws-guide and cloud-security-and-guardrails-guide, applied for the first time to a Pod instead of a CI job.

Resources

  1. Amazon EKS — Scale cluster compute with Karpenter and Cluster Autoscaler — the exact source for every citation in this lesson, including "EKS Auto Mode builds upon Karpenter."
  2. Karpenter — Documentation — the project's official documentation, directly referenced by AWS Docs.
  3. Cluster Autoscaler on AWS — Cluster Autoscaler's AWS-specific implementation.
  4. kubernetes-and-eks-in-production-guide (NIEVA), Module 3, lesson 7 — the HorizontalPodAutoscaler executed on kind, this lesson's central comparison point.