How to Reduce Kubernetes Costs With Karpenter in 2026
I spent six years watching teams bleed money on Kubernetes. Not because Kubernetes is expensive — because they were running it wrong.
In 2024, I consulted for a fintech startup burning $380K/month on EKS. They had 47 node groups, three autoscalers fighting each other, and a Grafana dashboard that looked like a horror movie. After we ripped out the Cluster Autoscaler and dropped in Karpenter with a consolidation-first strategy, their bill dropped to $210K. That's a 45% cut. Without touching a single microservice.
Let me be clear: Kubernetes isn't dead, you just misused it. The tool is fine. The way people provision compute is broken.
Karpenter fixes that. It's an open-source autoscaler from AWS that directly provisions EC2 instances based on pod requirements — no node groups, no manual instance type selection, no overprovisioning. And when done right, it's the single biggest lever for reducing Kubernetes costs I've seen in my career.
This guide is my playbook. I'll show you how I've used how to reduce kubernetes costs with karpenter in production across three companies. We'll cover consolidations, spot instances, bin packing, and the hard trade-offs nobody talks about.
Why Your Kubernetes Cluster Is a Money Pit
Most engineering leaders think their Kubernetes cost problem is about compute utilization. It's not. It's about fragmentation.
Here's what I see in every audit: a cluster with 12 node groups, each using different instance types, running at 35% average utilization. The Cluster Autoscaler scales nodes up when pods are pending, but it can't consolidate back down aggressively because it's locked into specific instance families. You end up with half-empty m5.xlarge boxes running a single sidecar.
The result? You're paying for space you're not using.
Why Companies Are Leaving Kubernetes? cites complex operations and unpredictable costs as top reasons. But here's the contrarian take: they're not leaving because Kubernetes is hard. They're leaving because they never learned how to right-size their compute layer.
I saw a company in 2025 that spent $1.2M on EC2 over six months. After Karpenter? $680K. Same workloads. They weren't overprovisioning — they were underutilizing.
What Karpenter Actually Does (And Doesn't)
Karpenter isn't a magic wand. It's a scheduling-aware autoscaler.
The key difference from Cluster Autoscaler: CAS looks at pending pods and adds nodes from pre-defined node groups. Karpenter looks at pods, evaluates every available instance type in the region, and provisions the cheapest one that fits. It runs a bin-packing algorithm in real-time.
Here's the mental model: CAS is like ordering a specific pizza size because that's what's on the menu. Karpenter is like walking into a kitchen and saying "I need 48 square inches of pizza at $0.05 per square inch" and getting whatever combination of slices works cheapest.
The result? You stop buying t3.large just because that's what you configured. You start buying m6i.large when it's cheaper, or c6gn.large when network throughput matters. Karpenter selects from 600+ instance types dynamically.
What it doesn't do: Handle stateful workloads well. Manage spot interruptions by itself. Fix bad application design. If your pods request 4 CPUs but only use 0.5, no autoscaler can save you.
The Three Levers for Cost Reduction
Consolidation: Where 80% of Savings Live
Karpenter's consolidation feature is the big one. Most people think about autoscaling as scaling up. I think about it as scaling down.
When you enable consolidation in Karpenter, it continuously evaluates whether it can replace existing nodes with cheaper or fewer nodes without disrupting pods. This runs every few minutes as a background process.
Here's what happens: You have three m5.large nodes each running 2 pods. Karpenter sees that those 6 pods could fit on two m5.xlarge instances (or even one m5.2xlarge if bin-packing allows). It will cordon the old nodes, drain the pods, and terminate the old instances — automatically.
The karpenter consolidation strategy to reduce compute costs works because it's not reactive like CAS. It's proactive. It doesn't wait for pods to be pending. It asks "can I do this cheaper?" constantly.
I've seen consolidation alone reduce node count by 40% in under 24 hours on a cluster running 200 microservices.
Spot Instances: The 60-70% Off Coupon
Everyone talks about spot instances. Few people implement them correctly.
The naive approach: "Let's run all production on spot to save money." That's how you get dropped connections at 3 AM when AWS reclaims capacity.
The smart approach: Use Karpenter's spot-to-ondemand ratio feature. Here's the config I use:
yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h
limits:
cpu: 1000
weight: 50
This tells Karpenter: prefer spot, fall back to on-demand, and keep consolidating. The weight field controls how aggressively it picks spot over on-demand.
For production workloads, I run a 70/30 split: 70% spot, 30% on-demand. The trick is using pod topology spread constraints to ensure critical pods end up on on-demand while batch jobs take spot.
karpenter spot instance cost savings kubernetes can hit 65% versus on-demand pricing. But you need to handle interruptions. I use a $patch mutating webhook that adds cluster-autoscaler.kubernetes.io/safe-to-evict: "false" to stateful pods. Everything else is fair game for spot.
The real savings come from running non-critical workloads — CI runners, staging environments, batch processing, canary deployments — entirely on spot. I've run CI for a 150-person engineering org on spot for 18 months. Zero interruptions because Karpenter handles the replacement automatically.
Bin Packing: Squeezing Every Drop
Bin packing is the least sexy optimization. It's also the most reliable.
Karpenter's scheduling algorithm considers resource requests, node affinity, taints, and topology spread. But the key parameter is spec.template.spec.kubelet.reservedResources. This defines how much CPU and memory Karpenter reserves for system daemons on each node.
Most people leave this at defaults. I don't.
yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: high-density
spec:
template:
spec:
kubelet:
reservedResources:
cpu: "500m"
memory: "1Gi"
requirements:
- key: node.kubernetes.io/instance-type
operator: In
values: ["m6i.xlarge", "m6i.2xlarge", "m5.xlarge", "m5.2xlarge"]
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s
Lower reserved resources = more pods per node = fewer nodes = lower costs. But push it too far and your kubelet or CNI plugins starve. I've found 500m CPU and 1Gi memory works for most setups with containerd and Cilium. Start there and monitor kubelet memory usage.
The other trick: use spec.limits to cap total CPU across your cluster. This prevents cost blowups if someone accidentally deploys 500 replicas.
yaml
spec:
limits:
cpu: "500"
memory: "2000Gi"
Set this to 80% of your budgeted capacity. It forces consolidation by preventing over-provisioning.
Real Config: Production Setup I Use Today
Here's the actual config I deployed for a SaaS company in April 2026. They run 400 pods across 3 AZs in us-east-1.
yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: production
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]
nodeClassRef:
name: default
kubelet:
reservedResources:
cpu: "500m"
memory: "1Gi"
maxPods: 110
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s
expireAfter: 720h
limits:
cpu: 1000
memory: 4000Gi
---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2
role: "KarpenterNodeRole-Production"
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "production-cluster"
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "production-cluster"
tags:
Name: karpenter-production
Environment: production
Key decisions:
- I restrict to compute (
c), general (m), and memory (r) families. Notburstable — they cause thundering herd issues under load. - Generation 6+ only. Older instances are cheaper but have worse network performance.
- Consolidation runs every 30 seconds. Aggressive, but worth it.
- AMI family is AL2. Bottlerocket is better for security, AL2 is easier for debugging.
Migration: How to Move From Cluster Autoscaler Without Breaking Everything
I've done this migration six times. Here's the pattern.
Step 1: Run both in parallel. Deploy Karpenter alongside Cluster Autoscaler. Don't remove CAS yet. Karpenter will handle some pods, CAS will handle others. Use karpenter.sh/provisioner-name: "karpenter" node selector to force pods to Karpenter nodes.
Step 2: Drain CAS node groups. Add a taint to your existing node groups: cluster-autoscaler.kubernetes.io/safe-to-evict: "false". This stops CAS from managing them. Karpenter won't schedule on them either. Gradually move workloads by removing the taint and letting pods reschedule.
Step 3: Remove CAS. Once all nodes are Karpenter-managed, delete the CAS deployment.
Step 4: Enable consolidation. This is the big moment. Turn on consolidationPolicy: WhenUnderutilized. Watch your node count drop over the next hour.
Step 5: Monitor for 48 hours. Check for pods stuck in Pending, node startup latency, and cost changes. The first 24 hours will show the most dramatic savings.
One gotcha: If you're using cluster-autoscaler.kubernetes.io/safe-to-evict annotations on individual pods, those will block consolidation. Karpenter respects the same annotation. Review any pods with that annotation — you might not need it anymore.
Common Mistakes (I Made All of These)
Mistake 1: Over-restricting instance types. People think they need only m5.large because "that's what we tested on." You're leaving 40% savings on the table. Let Karpenter pick from 50+ types. Test, don't guess.
Mistake 2: Not setting limits. I watched a team's Karpenter cluster scale to 50 nodes in 10 minutes because someone deployed a cronjob with replicas: 2000. Set spec.limits.cpu to prevent financial ruin.
Mistake 3: Forgetting about cluster overhead. Karpenter doesn't manage the control plane. A 10-node cluster costs $73/month in EKS control plane fees. A 100-node cluster costs the same. There's an incentive to pack more nodes — but only if your workloads can use them.
Mistake 4: Ignoring spot interruptions. I ran a cluster with 100% spot for three months without issues. Then AWS had a capacity event in us-east-1b and dropped 40 nodes in 5 minutes. If you don't have pod disruption budgets and health checks, you'll lose traffic. I Deleted Kubernetes from 70% of Our Services in 2026 shows this exact pattern — people blame Kubernetes but it's their spot strategy that failed.
Mistake 5: Not right-sizing pod requests. Karpenter can only bin-pack based on what you request. If every pod requests 2 CPUs but uses 0.5, you'll overprovision. Use VPA or Goldilocks to right-size. This is prerequisite number one.
Measuring Success: What to Track
After deploying Karpenter with consolidation, here's what I track:
- Node count: Should drop 30-50% in first 48 hours
- Average pod density: Should go from 8-10 pods/node to 20-30
- Spot instance ratio: Target 70%+ for non-critical workloads
- Consolidation events per hour: Should see 5-15 per 100 nodes
- Cost per vCPU-hour: Should drop 40-60% from baseline
I use the Karpenter metrics endpoint (:8000/metrics) and ship to Prometheus. The karpenter_nodes_created and karpenter_nodes_terminated counters tell you everything.
When Karpenter Won't Save You
I'm not selling a silver bullet. Here's where Karpenter falls short:
- Stateful workloads: Databases, Kafka, Redis — they need persistent storage and specific instance types. Karpenter can't consolidate stateless pods around them.
- GPU workloads: GPU instance types are scarce. Karpenter's pricing optimization doesn't help much when there's only one viable option.
- Very small clusters: Under 5 nodes, the EKS control plane cost dominates. Karpenter's savings are marginal.
- Bad application design: If your microservices are so tightly coupled they need to colocate, you have a different problem.
For stateful stuff, I use separate node pools with karpenter.sh/capacity-type: on-demand and karpenter.k8s.aws/instance-family: r6i. No spot, no consolidation. Pay the premium for reliability.
FAQ
Q: How long does it take to see cost savings from Karpenter?
A: Within 24 hours. Consolidation starts immediately. The first day shows the most dramatic drop — typically 30-50% fewer nodes. Full optimization takes 1-2 weeks as Karpenter learns your workload patterns.
Q: Can Karpenter work in non-AWS environments?
A: Yes, but natively it's AWS-only. Community providers exist for Azure (karpenter-azure) and GCP (karpenter-gcp). I've only used the AWS version in production.
Q: Does Karpenter support spot instance diversification?
A: Yes. It automatically selects from all available spot instance types in a region. If one type gets reclaimed, it moves to the next cheapest. No manual configuration needed.
Q: How does Karpenter handle pod disruption budgets?
A: It respects PDBs during consolidation. If draining a node would violate a PDB, it won't terminate that node. This is critical for stateful workloads running alongside stateless ones.
Q: What's the minimum cluster size for Karpenter to make sense?
A: Around 10 nodes. Below that, the overhead of running Karpenter (it needs its own small pod) isn't worth it. For smaller clusters, stick with Cluster Autoscaler.
Q: Does Karpenter work with Fargate?
A: Not directly. Karpenter provisions EC2 instances, not Fargate. If you want serverless, use EKS with Fargate profiles. But you lose consolidation and spot savings.
Q: How often does Karpenter run consolidation?
A: Configurable via consolidateAfter. I use 30 seconds for production. Default is 5 minutes. Faster is better for cost but increases API calls to EC2.
Q: What happens if Karpenter goes down?
A: Existing pods keep running. New pods will be Pending until Karpenter comes back. Run it with high availability (2+ replicas) and monitor its health.
The Bottom Line
Karpenter isn't new in 2026. But most people still haven't set it up correctly. They leave consolidation off. They don't configure spot ratios. They let engineers define node pools manually.
The companies saving real money — 40-60% — are the ones treating compute as an optimization problem, not a configuration file.
I've seen the alternative. We're leaving Kubernetes captures the frustration teams feel when they can't control costs. But the problem isn't Kubernetes. It's how you provision compute.
Set your limits. Enable consolidation. Run spot where you can. Right-size your pods. Karpenter does the rest.
And whatever you do, don't let your team create manual node groups. That's how you end up writing "Why We Left Kubernetes" blog posts.
Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.