Skip to content
Journal
CloudMay 20, 20267 min read

Getting Cost Visibility in Kubernetes Without Losing Your Mind

FinOps on Kubernetes is genuinely hard. Namespaces, shared nodes, and bursty workloads make attribution a mess. Here is the approach we use to make every dollar legible.

Almost every team we audit is spending 30 to 40 percent more than they need to on Kubernetes — and, more tellingly, almost none of them can say which team or service is responsible for the bill. The two facts are related. You cannot optimize what you cannot attribute.

Why Kubernetes cost is so hard to see

A traditional cloud bill maps spend to resources: this VM, that database, this load balancer. Kubernetes breaks that mapping. A single node runs pods from many teams. A pod's cost depends on its requests, its actual usage, and what else happens to be scheduled alongside it. The cloud bill says "you ran 40 nodes." It does not say why.

The result is a bill that is accurate but useless — correct to the cent, and impossible to act on.

Start with requests, not usage

The instinct is to chase actual CPU and memory usage. Resist it at first. In Kubernetes, what you are billed for is largely driven by requests, because requests determine how many nodes the scheduler has to keep around. A pod requesting 4 CPUs but using 0.2 is not a utilization problem — it is a capacity reservation you are paying for whether the pod uses it or not.

So the first pass is always the same:

  • Pull requests versus actual usage for every workload, over a representative window.
  • Rank by the gap between requested and used, weighted by replica count.
  • Rightsize the top of that list. The distribution is almost always long-tailed — a handful of workloads explain most of the waste.

Attribute by namespace, then by label

Cost attribution needs a key. Namespaces are the coarse one; labels are the precise one. We standardize on a small set of required labels — team, service, env — and enforce them with policy so nothing schedules without them.

# enforced at admission — no label, no schedule
metadata:
  labels:
    team: payments
    service: checkout-api
    env: production

Once every pod carries those labels, the shared-node problem becomes solvable. You split a node's cost across the pods running on it, weighted by their requests, and roll that up by label. Now the bill reads "payments spent $X, checkout-api was $Y of it" — a sentence an engineering manager can act on.

Idle is the silent line item

The last piece is the cost of capacity nobody is using: half-empty nodes, over-provisioned headroom, environments left running over the weekend. This shows up as the difference between what you provisioned and what your pods requested.

Showback turns cost from an infrastructure problem into a team problem — and teams optimize what they can see on their own dashboard.

The fix is rarely heroic. Bin-packing improvements, a cluster autoscaler tuned to scale down aggressively, and a scheduled scale-to-zero for non-production environments typically recover the bulk of it.

Make it a habit, not a project

The mistake is treating cost as a one-time cleanup. Workloads drift, traffic grows, someone bumps a request "just to be safe." We wire the attribution into a weekly report and an alert on anomalies, so the next 11-percent compounding month gets caught in week one — not in the quarterly review.

Cost visibility on Kubernetes is not a dashboard you buy. It is a label discipline you enforce, an attribution model you trust, and a habit you keep.

// next

Questions about this? Let’s talk.

A senior engineer on the other end — not a salesperson. We'll tell you what we'd fix first.