Kubernetes Cost Optimization: Right-Sizing Pods, Nodes, and Namespaces
We covered multi-region Kubernetes architecture in our scaling best practices guide. This one is about the other half of the K8s conversation: cost. In our experience, Kubernetes clusters routinely run at 30-40% actual utilization against what's requested — meaning enterprises are often paying for roughly double the compute they need, purely from conservative resource requests nobody has revisited since they were first set.
Why Kubernetes Waste Is Different From VM Waste
An oversized EC2 instance is a single line item you can spot on a bill. Kubernetes waste is distributed — hundreds of pods each requesting slightly more CPU and memory than they use, compounding into nodes that are bin-packed based on inflated numbers. This is exactly why generic cloud cost tools that don't understand container-level allocation miss the majority of Kubernetes waste; it's invisible at the account level and only visible at the pod level.
Step 1: Measure Before You Touch Anything
Never right-size off gut feel or a single day of metrics. Run the Vertical Pod Autoscaler in recommendation-only mode (updateMode: "Off") for at least 1-2 weeks, capturing at least one peak-traffic period, before changing any resource requests. Tools like Goldilocks visualize VPA recommendations across a namespace, making this a lot faster than querying Prometheus manually pod by pod.
Step 2: Right-Size Requests to P95, Not Average
Setting requests at average usage guarantees you'll hit OOMKills and CPU throttling during normal traffic variance. Our standard approach:
- CPU requests: Set at P90-P95 of observed usage over the measurement window.
- Memory requests: Set slightly more conservatively (P95-P99) since OOMKills are more disruptive than CPU throttling.
- Limits: Set CPU limits generously above requests (or unset, depending on your noisy-neighbor tolerance) and memory limits at a level that absorbs legitimate spikes without allowing a true runaway process to take down the node.
Step 3: Fix the Node Layer with Karpenter
Traditional Cluster Autoscaler scales pre-defined node groups, which forces you to guess the "right" instance types in advance. We generally migrate AWS-based clients to Karpenter, which calculates the exact instance type and size needed for pending pods and provisions it directly — no pre-defined node groups, no guessing, and typically faster provisioning (seconds rather than minutes) with tighter bin-packing.
Step 4: Use Spot for Fault-Tolerant Workloads
Stateless services behind a Horizontal Pod Autoscaler with multiple replicas are ideal Spot candidates — a single node interruption just means Kubernetes reschedules the affected pods elsewhere. We cover the broader Spot strategy in our AWS discount guide; the same principles apply directly to Kubernetes node pools.
Step 5: Namespace-Level Quotas and Attribution
Without ResourceQuotas per namespace, individual teams have no natural ceiling on requests, and cost attribution back to teams (per our cost allocation guide) becomes guesswork. Setting namespace quotas does double duty: it caps runaway resource requests and gives you a clean unit for showback reporting.
What This Looks Like in Practice
In a recent engagement covered in our Kubernetes scaling post, applying this right-sizing process across a client's clusters alongside a migration to Karpenter reduced their node-hour costs by roughly a third, without a single additional OOMKill incident in the following month — because the right-sizing was based on measured P95 data, not a guess.
Ongoing Governance, Not a One-Time Project
Resource requests drift again as code changes and traffic patterns shift. We recommend re-running the VPA recommendation pass quarterly, and using continuous Kubernetes cost visibility inside FinOps Co-Pilot to catch newly-introduced over-provisioning before it becomes the new normal. Want a cluster audit? Talk to our DevOps team.
Frequently Asked Questions
What is the biggest source of Kubernetes waste?
Over-provisioned resource requests, consistently — conservative "just in case" sizing that directly drives oversized, underutilized nodes.
Is Karpenter worth switching to from Cluster Autoscaler?
For AWS-based clusters, yes in most cases — it provisions the exact instance type needed in seconds rather than scaling pre-defined node groups.
How do you right-size without causing OOMKills?
Use historical usage data over 1-2 weeks including peak load, set requests near P95 usage, and set limits higher to absorb short spikes.