Talk to us
WhatsApp us

Free cloud cost review: we will find the waste in your AWS or Azure bill in 5 business days. Book it

FinOps & cloud cost

Kubernetes cost optimisation: where the money actually goes

Most Kubernetes waste is one thing: resource requests set far above what pods actually use. Everything else follows from that.

  • Updated
  • 3 min read

The short answer

Most Kubernetes overspend comes from resource requests set far above actual usage, because the scheduler reserves capacity based on requests rather than consumption. Fixing requests against observed utilisation typically reclaims the most, followed by cluster autoscaling, bin-packing improvements and moving fault-tolerant workloads to spot capacity.

Key takeaways

  • The scheduler reserves what you request, not what you use
  • Right-size requests before touching node types or autoscaling
  • Spot capacity suits stateless, interruption-tolerant workloads
  • Without per-namespace showback, no team owns the number
Kubernetes cost optimisation: where the money actually goes — illustration

Part of our guide to FinOps: how to actually reduce a cloud bill.

Kubernetes makes cost harder to see. You pay for nodes, but you think in pods, and the relationship between the two is mediated by a scheduler making decisions on your behalf.

Requests are the whole problem

The scheduler places pods based on their resource requests, not their actual usage. Request 2 CPU and use 0.1, and the cluster reserves 2 CPU — that capacity is unavailable to anything else, and you are paying for the node that provides it.

In most clusters this single factor accounts for the majority of waste. Requests get set once, copied between services, and never revisited. A ratio of requested to used capacity of five or ten to one is common.

Fix it by looking at actual consumption over a few weeks and setting requests near the observed p95, with limits above that for burst. The Vertical Pod Autoscaler in recommendation mode is useful for generating the numbers even if you do not let it apply them automatically.

One caution: requests that are too low cause scheduling problems and noisy-neighbour effects. This is a right-sizing exercise, not a race to zero.

Then look at the nodes

Cluster autoscaling. Without it, node count is set for peak and paid for permanently. Cluster Autoscaler or Karpenter add and remove nodes with demand. Karpenter in particular selects instance types to fit pending pods, which handles bin-packing better than a fixed node group.

Bin-packing. Nodes sized poorly relative to typical pod size leave stranded capacity — a large node with one small pod on it is mostly wasted. Mixed instance sizes let the scheduler pack more efficiently.

Spot capacity. Stateless services that tolerate interruption can run on spot at a substantial discount. Use a mixed strategy: on-demand for baseline capacity and anything stateful, spot for the elastic portion. Ensure pod disruption budgets and graceful shutdown handling are in place first.

ARM nodes. Where the workload supports it, ARM-based instances offer better price-performance. Most containerised applications do; the blocker is usually that nobody has built a multi-architecture image and tried it.

The parts people forget

Control plane and per-cluster overhead. Several small clusters cost meaningfully more than one well-segmented cluster with namespaces and network policies. Consolidate where the isolation requirement does not genuinely demand separate clusters.

Idle namespaces. Development namespaces from finished projects hold requests and therefore nodes. They need the same expiry treatment as any other non-production environment.

Logging volume. Cluster logging at debug level across every pod can rival compute cost. Set levels deliberately and apply retention.

Attribution

Without per-namespace or per-team cost visibility, Kubernetes spend is a single number nobody owns. Tools such as Kubecost, or native cost allocation using namespace labels, split the bill by team or product.

This matters more in Kubernetes than almost anywhere else, precisely because the shared-cluster model hides who is consuming what. Once a team can see its own footprint, requests get tuned without anyone having to mandate it.

Frequently asked questions

Right-sizing resource requests. The scheduler reserves capacity based on requests rather than usage, so requests set far above actual consumption directly inflate node count.

For stateless, interruption-tolerant workloads with pod disruption budgets and graceful shutdown, yes — usually as the elastic portion of a mixed strategy, with on-demand covering baseline and stateful services.

Fewer, larger clusters are generally cheaper — per-cluster overhead and poor bin-packing add up. Separate clusters when there is a genuine isolation or regulatory requirement, not by default per team.

Keep reading