Kubernetes nodes are the compute layer. When pods need more capacity than the current nodes provide, something has to provision more nodes. Two tools dominate that job: the Cluster Autoscaler and Karpenter. They take different approaches, and the choice matters more than most teams realize.
This post is what each one actually does, where each shines, and the patterns that emerge in production.
The Old Way: Cluster Autoscaler
Cluster Autoscaler (CA) is the original. It works with node groups defined ahead of time — Auto Scaling Groups in AWS, MIGs in GCP, Scale Sets in Azure. When pods cannot be scheduled, CA tells the cloud provider to scale a node group up.
# AWS Auto Scaling Group, configured in advance
- name: app-nodes
instanceType: m5.large
minSize: 3
maxSize: 50
desiredSize: 5
CA watches for unschedulable pods. It picks a node group whose instance type can fit them. It tells the ASG to add a node. The cloud provisions; the node joins; the pod schedules.
For scale-down, CA looks at underutilized nodes and removes them — but only if pods can be rescheduled elsewhere.
The model is straightforward. The constraint is pre-defined node groups. If you defined m5.large and a workload needs more memory than m5.large provides, you need a different node group.
The New Way: Karpenter
Karpenter, from AWS (now CNCF), takes a different approach. There are no pre-defined node groups. Karpenter looks at unschedulable pods, decides what instance type fits best, and provisions one — picking from the entire AWS catalog.
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
Constraints say "amd64 or arm64" and "spot or on-demand." Karpenter picks the cheapest instance type that meets the constraints and the pod's resource requirements.
The model is more dynamic. The constraint is requiring Karpenter to be on AWS (with some support for Azure now). The benefit is significantly better cost optimization and faster provisioning.
Speed Comparison
Cluster Autoscaler: unschedulable pod → CA decision → ASG scale → cloud provisions → node joins. Typically 2-5 minutes end-to-end.
Karpenter: unschedulable pod → Karpenter decision → direct EC2 RunInstances → node joins. Typically 30-60 seconds end-to-end.
The speed difference is significant for bursty workloads. CA's ASG path adds minutes of latency that Karpenter avoids.
Cost Comparison
This is where Karpenter dramatically wins.
Cluster Autoscaler is constrained to the node groups defined ahead of time. If a workload needs 4 vCPUs and 16 GB and your only group is m5.xlarge (4 vCPU, 16 GB), you get it. If the workload needs 2 vCPUs and 8 GB, you still get m5.xlarge — there is no smaller node group.
Karpenter picks the right size for the actual workload. A pod needing 2 vCPUs and 8 GB gets a m5.large. The over-provisioning that comes with fixed node groups disappears.
Karpenter also handles spot instances better. It can:
- Pick across many spot instance types to maximize availability
- Move spot workloads to a different instance type when one becomes unavailable
- Mix spot and on-demand in ways CA cannot
Teams that migrate from CA to Karpenter typically see 20-40% reduction in compute cost. The savings come from both bin-packing and spot optimization.
Scheduling Decisions
CA respects affinities, anti-affinities, taints, and tolerations. So does Karpenter. The pod scheduling experience is similar.
The difference is what happens when no existing node fits:
- CA: pick a node group whose template fits, scale up.
- Karpenter: provision a new node sized to fit, considering many instance types.
For workloads with complex resource requirements (memory-heavy, GPU, ARM), Karpenter's flexibility matters more.
Drift Handling
Karpenter has a feature CA does not: drift detection and remediation. If a node's underlying configuration drifts from what was declared (AMI changes, kernel updates), Karpenter can replace it.
spec:
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h # nodes get replaced after 30 days
This makes node lifecycle management more automatic. Instead of "we have a sprint to roll the cluster," nodes naturally cycle out as part of normal operation.
CA has nothing equivalent. Node OS updates require manual node group recreation.
Multi-Tenancy
For clusters serving multiple teams or workloads:
CA: each tenant typically gets its own node group with limits. Strong isolation.
Karpenter: multiple NodePools with different constraints can serve different tenants. Slightly less rigid isolation; can be more flexible.
For strict multi-tenancy with hard resource limits per tenant, CA's node group model is clearer. For flexible self-service, Karpenter's model is better.
EKS Auto Mode
In late 2024, AWS released EKS Auto Mode, which bakes Karpenter directly into EKS. New EKS clusters can opt into Auto Mode and get Karpenter scaling without separately installing it.
This is a strong signal of where AWS is investing. Existing CA setups continue to work; new EKS clusters should at least evaluate Auto Mode.
When to Use Cluster Autoscaler
- Multi-cloud or non-AWS environments (Karpenter's AWS support is most mature)
- Existing investment in node groups and ASGs
- Strict cost predictability requirements (Karpenter's instance variability surprises some finance teams)
- Workloads with very stable resource needs (the bin-packing optimization does not pay off)
When to Use Karpenter
- AWS EKS clusters
- Workloads with varying resource needs (bin-packing helps)
- Heavy use of spot instances
- Multiple workload types in one cluster
- Teams that have engineering capacity to learn Karpenter's model
When to Use Both
Some teams run both: CA for stable system workloads, Karpenter for variable application workloads. This is rare and operationally complex. Most teams should pick one.
Operational Patterns
For Karpenter:
- Define multiple NodePools for different workload classes (general, GPU, memory-heavy)
- Use
Provisionerto set instance type constraints (mix spot and on-demand) - Monitor
karpenter_pod_statemetrics for stuck pods - Set
expireAfterto force node rotation
For CA:
- Define node groups for the workload mix you have (not the workload mix you wish you had)
- Tune the
--scale-down-delay-after-addand--scale-down-unneeded-timeparameters - Use Priority Expander to prefer cheaper node groups
- Watch for thrashing (rapid scale up/down)
Migration Path
Migrating from CA to Karpenter:
- Install Karpenter alongside CA (do not delete CA yet)
- Create NodePools with constraints matching your workload patterns
- Cordon and drain a single CA node group; verify Karpenter takes over
- Gradually move workloads as you trust the new setup
- Remove CA-managed node groups once Karpenter is handling everything
The migration is typically a few weeks for a real cluster. The savings start showing up immediately as Karpenter takes over scheduling.
What Stays the Same
Both tools handle:
- Pod-driven scaling (based on unschedulable pods, not metrics)
- Scale-down based on utilization
- Respecting
PodDisruptionBudgets - Taints and tolerations
- Node affinity
The HPA (Horizontal Pod Autoscaler) is upstream of both — it scales pods, not nodes. CA and Karpenter respond to the pod-level pressure HPA creates.
A Practical Default
For a new AWS EKS cluster in 2026: Karpenter, almost always. The cost savings and operational benefits are substantial enough that "use the old way" needs a specific reason.
For existing CA setups: evaluate migration. The savings usually justify the migration effort within months.
For non-AWS clusters: Cluster Autoscaler remains the default. Karpenter's other-cloud support is improving but is not yet as mature.
Evaluating node scaling for a Kubernetes cluster that has hit capacity limits or is overspending on idle capacity? We help teams pick the right autoscaler and tune it for the workload mix. scopeforged.com