🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Karpenter vs Cluster Autoscaler — Which Node Autoscaler Should You Run on EKS?

Cluster Autoscaler has been the default for years, but Karpenter provisions nodes faster and bin-packs better. Here's a real comparison of both, with configs, to help you decide for your EKS cluster.

DevOpsBoysJun 16, 20264 min read
Share:Tweet

If you're running Kubernetes on AWS, you need something deciding when to add or remove nodes based on pending pods and underutilized capacity. For years that was Cluster Autoscaler by default. Karpenter changed the calculus — but it's not automatically the right choice for every cluster.

How They Fundamentally Differ

Cluster Autoscaler scales existing Auto Scaling Groups (ASGs). You define node groups with instance types ahead of time, and Cluster Autoscaler adds/removes instances within those predefined groups based on pending pods.

Karpenter provisions nodes directly — no ASGs in the loop. You define constraints (instance families, zones, architectures) and Karpenter picks the optimal instance type and size for each batch of pending pods, in real time, without you pre-defining node groups.

Configuration Comparison

Cluster Autoscaler — you pre-define node groups:

yaml
# Each node group is a fixed instance type — you manage many of these
# for different workload shapes (CPU-heavy, memory-heavy, GPU, etc.)
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
nodeGroups:
  - name: general-purpose
    instanceType: m5.xlarge
    minSize: 2
    maxSize: 10
  - name: memory-optimized
    instanceType: r5.2xlarge
    minSize: 0
    maxSize: 5

Karpenter — you define constraints, it picks the instance:

yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["4"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
  limits:
    cpu: 1000
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized

One NodePool replaces a dozen hand-maintained node groups, and Karpenter chooses the cheapest instance type that fits the pending pod's actual resource request — not whatever fixed-size node group happened to have room.

Provisioning Speed — The Difference You'll Actually Feel

Cluster Autoscaler: detects pending pod → scales ASG → ASG launches instance → 
  instance joins cluster → kubelet ready
  Typical: 3-5 minutes

Karpenter: detects pending pod → directly calls EC2 RunInstances with optimal type → 
  instance joins cluster → kubelet ready
  Typical: 30-60 seconds

For workloads with bursty scaling needs — CI/CD runners, batch jobs, traffic spikes — this difference is the entire reason teams migrate.

Bin Packing and Cost

Cluster Autoscaler scales within fixed-size node groups, so if your pending pods need 2.5 vCPU and your only available node group is m5.xlarge (4 vCPU), you get a whole m5.xlarge for a 2.5 vCPU pod — wasted capacity baked into the node group design.

Karpenter evaluates the actual pending pod requirements and launches the cheapest instance type that fits, including spot instances when allowed:

yaml
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]

In practice, teams migrating from Cluster Autoscaler to Karpenter commonly report 20-40% lower node costs purely from better bin-packing and spot utilization, independent of any traffic pattern change.

Consolidation — Karpenter's Other Big Advantage

yaml
disruption:
  consolidationPolicy: WhenEmptyOrUnderutilized
  consolidateAfter: 30s

Karpenter actively looks for opportunities to consolidate workloads onto fewer, better-utilized nodes and terminates the now-empty ones. Cluster Autoscaler only scales down nodes that are completely empty — it doesn't actively repack underutilized nodes the way Karpenter does.

Where Cluster Autoscaler Still Makes Sense

You're not on AWS, GCP, or Azure with Karpenter support, or you're running on-prem with cluster-api — Karpenter's AWS/Azure/GCP cloud provider integrations are the mature ones; broader cloud-provider coverage is still growing.

Your node groups map to compliance/governance requirements — some orgs require every node's instance type to be pre-approved and explicitly tracked, which fits Cluster Autoscaler's static node group model more naturally than Karpenter's dynamic provisioning.

You have a small, stable cluster where autoscaling speed and bin-packing efficiency don't matter much — the migration effort isn't worth it for a cluster running 5 nodes with predictable load.

Migration Reality Check

You can run both during migration — Karpenter and Cluster Autoscaler can coexist on different node groups while you validate Karpenter's behavior on a subset of workloads before cutting over fully.

bash
# Tag existing ASG-based node groups to exclude them from Karpenter's view
# while you validate Karpenter on new NodePools in parallel
kubectl label nodes -l eks.amazonaws.com/nodegroup=general-purpose \
  karpenter.sh/do-not-disrupt=true

Bottom Line

For new EKS clusters in 2026, Karpenter is the right default — faster scaling, better bin packing, less node group sprawl to maintain. Cluster Autoscaler remains a reasonable choice for stable, predictable workloads or non-AWS environments where Karpenter's cloud provider support isn't there yet.

Full Karpenter setup walkthrough: Karpenter Node Autoscaling Complete Guide

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments