New recipes every week

Turn Complexity Into
Cloud Recipes

Learn Kubernetes, AI, DevOps and DevSecOps the CloudChef way. Practical guides, real-world examples, no fluff.

Free forever No paywall Practical guides Real-world examples
50+Guides
WeeklyNew posts
K8s + AITop topics
FreeAlways
Thursday, July 2, 2026 ⏱ Calculating...

I Changed Two Lines of YAML and Cut Our AWS Bill by 40%.

CC
CloudChef
thecloudchef.io
I Killed 40% of My EKS Cost

No clickbait here. This is the real before, the real after, and the real numbers from a cluster I actually worked on.

Grab a coffee. This one's short, and it's honestly a little embarrassing how small the fix was.


😀 Where We Started

EKS cluster, already on Karpenter, already "optimized" according to whoever set it up first. Average node utilization sitting around 35%. Monthly EC2 spend on this one cluster: roughly $14,000.

Looked fine on paper. Nobody was on fire. Nobody was really looking closely either — which, funny enough, is exactly how this kind of leak survives.


🧠 The One Thing That Was Wrong

The NodePool's disruption block looked like this:

disruption:
  consolidationPolicy: WhenEmpty
  consolidateAfter: 30m

πŸ‘‰ WhenEmpty only removes nodes once they're completely empty. A node running one tiny pod at 5% utilization just sits there forever — since technically, it's never "empty." It's like leaving a whole oven on for a single cracker.


⚙️ The Fix

disruption:
  consolidationPolicy: WhenEmptyOrUnderutilized
  consolidateAfter: 1m

That's it. Two lines.

πŸ‘‰ WhenEmptyOrUnderutilized tells Karpenter to actively repack pods from underused nodes onto fewer, better-used ones — not just wait politely for nodes to go fully idle first.


πŸ“Š What Changed

flowchart LR A[Before: WhenEmpty] --> B[Nodes at 35% util sit forever] C[After: WhenEmptyOrUnderutilized] --> D[Pods repacked, nodes terminated] B --> E["$14,000/mo"] D --> F["$8,400/mo"]

Within about a week of normal traffic cycling through, average node utilization climbed from 35% to roughly 68%. Node count during off-peak hours dropped by nearly half.


πŸ” How We Verified It Wasn't a Fluke

We tracked daily AWS Cost Explorer EC2 spend for this cluster's tagged resources across two full weeks — one before the change, one after. Same traffic pattern, same workloads, no deploys that would've shifted resource requests.

πŸ‘‰ The drop held steady. Not a one-day blip.


⚠️ Why This Gets Missed So Often

WhenEmpty genuinely sounds like the safer default — "don't touch anything that's still doing work" reads as cautious and responsible. That instinct is reasonable. It's also exactly why teams set it and never revisit it.

Nobody audits disruption policy after initial setup. It's not a flashy line in a YAML file. It just quietly costs money in the background, like a subscription you forgot you signed up for.


πŸ”₯ CloudChef Pro Tip

Run this check today:

kubectl get nodepool -o jsonpath='{range .items[*]}{.metadata.name}{": "}{.spec.disruption.consolidationPolicy}{"\n"}{end}'

πŸ‘‰ If anything says WhenEmpty instead of WhenEmptyOrUnderutilized, you likely have the exact same leak sitting in your cluster right now.

πŸ”— Continue Your CloudChef Journey


πŸ“š References


πŸš€ Final Thoughts

This wasn't a rewrite. Wasn't a migration. Wasn't a new tool. It was one field, in one YAML block, that nobody had looked at since the cluster went live.

πŸ‘‰ Go check yours before you assume your Karpenter setup is already optimized. It probably isn't.


πŸ”₯ Trending CloudChef Recipes

⭐ Popular CloudChef Recipes

No comments:

Post a Comment

πŸ’‘ Found this useful?

Share it with your Team or DevOps Friends πŸ‘‡