The cloud bill answers the question «how much does an EC2 instance cost», but stays silent on how much your payments-api costs. Dozens of workloads share a single node, and the bill cannot tell them apart. Per CNCF data for 2026, average Kubernetes cluster utilization sits at 35–50%: half of the paid capacity idles, and nobody sees whose half it is. Up to 35% of cloud spend is preventable waste, and the first reason it is not prevented is that there is nobody to charge it to. FinOps starts not with optimization but with allocation: who spends how much.
Why Kubernetes breaks cloud billing
Three problems that traditional cloud does not have. Shared infrastructure: billing operates on instances, not workloads — «EC2 = $X», but never «pod payments-api = $Y». The overprovisioning trap: an engineer whose service once died from OOM doubles the memory request; individually rational, collectively wasteful — and this defensive headroom is the main source of waste. The timing problem: a pod that burned excess memory for 72 hours and died three weeks ago is invisible in the monthly bill — slow billing signals never catch ephemeral resources.
Only one conclusion follows: cost has to be measured at pod level, in real time.
OpenCost: an engine, not a dashboard
OpenCost is a CNCF Incubating project (Apache 2.0) that grew out of the cost-allocation engine of Kubecost; contributors include AWS, Google and Microsoft, and the stated goal is to become «the Prometheus of cost monitoring». The mechanics are transparent: the engine takes Prometheus metrics (kube_pod_container_resource_requests) plus cloud pricing and splits it out: pod cost = CPU request × CPU-hour price + memory request × memory price + storage (PVC) + network. It installs with a single helm install pointed at Prometheus; the outside interface is an API like GET /allocation?window=1d&aggregate=namespace.
The main pitfall: the built-in OpenCost UI is a thin viewer, not a data store. It keeps a limited in-memory window and «loses» history after roughly a week — and that is not a bug. The intended architecture is different: OpenCost exports cost metrics back into Prometheus or VictoriaMetrics, and the dashboard lives in Grafana. Whoever builds reporting on the built-in UI quickly hits a wall.
OpenCost, Kubecost and AWS SCAD: two solutions, not three
A common confusion is to treat them as a three-way race. OpenCost and Kubecost are one class and one engine: real-time allocation inside the cluster. The choice between them is effort versus control: OpenCost is a vendor-neutral engine that needs Prometheus and Grafana; Kubecost is the same engine plus a UI with retention and savings recommendations, free for a single cluster, with multi-cluster and SSO starting at ~$449/month (the project is owned by IBM). For single-cluster EKS there is a free EKS-optimized bundle.
AWS SCAD is a different category: a billing feature that splits EC2 cost down to pod level right inside the billing data. The data lands only in CUR — Cost Explorer never sees it, querying goes through Athena. In return, SCAD reconciles with the real bill — Savings Plans, RI and Spot included, whereas OpenCost and Kubecost price everything at on-demand list rates and will not match the invoice. The mature setup keeps both: OpenCost or Kubecost for engineering efficiency («where is the waste right now»), SCAD for finance-grade chargeback («what to charge to which team»).
Idle cost and allocation rules
The base rule: namespace = team. Finer-grained — allocation by labels (team, cost-center, service). A pod without resources.requests is not allocated at all — there is nothing to charge it with; the requests requirement belongs in an admission policy via Kyverno or Gatekeeper.
A separate category is idle cost: (node capacity − sum of requests) × node price. Hiding it is not an option: either spread it pro rata across namespaces, or create a dedicated __idle__ namespace — so the very fact of overprovisioning stays visible on the dashboard. The anti-pattern is one namespace shared by several teams: allocation turns into fiction.
From allocation to unit economics
The next level is the cost of a business unit: cost per request, cost per tenant. A PromQL query divides the namespace cost metric by the business metric of the service — and the dashboard shows «$X per million requests, trending Y% per month». From there, cost becomes a quality gate just like error rate: an AnalysisTemplate in Argo Rollouts blocks the deploy when cost per request crosses the threshold.
For basic cases there is also a path without OpenCost: AWS imports K8s labels as Cost Allocation Tags, and «how much did team X spend» shows up directly in Cost Explorer. But idle allocation, network attribution and unit-economics queries stay out of reach on that path.
The rollout fits in a week: OpenCost exporting into Prometheus, a Grafana dashboard, labels on workloads, idle made explicit. The top 10 namespaces usually carry ~80% of the spend — start there. Mature FinOps practices reach 20–54% savings, but the first step is always the same: see who spends. Optimization without allocation is guesswork.