Splitting a shared cluster's bill so teams believe the number
Allocation by requests or by usage creates opposite incentives, shared costs start the argument, and showback before chargeback is what stops the whole exercise being rejected.
The cloud bill shows one line: a node pool. The cluster runs fourteen services owned by six teams. Finance asks which team is responsible for the increase, and the honest answer is that nobody knows, so the platform team owns all of it. Since the platform team cannot change any of the workloads, the cost has an owner who cannot act and actors who have no owner.
That is the problem cost allocation solves. It is less a tooling problem than a modelling one, because the arithmetic is easy and the argument about the arithmetic is not.
How a node's cost reaches a pod
The mechanism is the same in every tool. Take the hourly cost of the node from the provider's rate, including whatever discount actually applies. Work out each pod's share of the node's CPU and memory over the time it ran there. Multiply.
The tools differ in polish rather than principle. OpenCost is the CNCF project that implements the model and exports the allocation as metrics; it is free, it is the reference implementation, and it is enough for most teams. Kubecost is built on the same core with a commercial product around it, adding retention, multi-cluster views, recommendations and governance features. Start with OpenCost, move if you need the surrounding product rather than the number.
Both need accurate node pricing to be worth anything. If you have reservations, committed use discounts or a savings plan, the list price overstates the bill substantially and every team will correctly dismiss the numbers. Feed in the real rates, or at minimum a blended effective rate, before you show anyone the first report.
Requests or usage, and why the answer is requests
This is the decision that shapes behaviour, and teams often get it backwards.
Allocating by usage charges a team for the CPU and memory its pods actually consumed. It feels fair and it is wrong, because it does not reflect what the cluster had to buy. A pod requesting 4 cores and using 0.2 forces the scheduler to reserve 4 cores; the cluster bought them and somebody paid. If you allocate by usage, that team pays for 0.2 and everyone else subsidises the reservation.
Allocating by requests charges for what was reserved, which is what actually drove the node count. It creates precisely the right incentive: a team lowers its bill by making its requests match reality, which is the same action that improves cluster density.
The standard approach is the maximum of request and usage, so a team that under-requests and bursts is not rewarded either. Report both numbers side by side. The ratio between them is the single most actionable figure you can hand a team, and it is the same number that drives why an EKS cluster costs twice what it should and AKS node pool spend.
Shared costs are where the argument happens
Between a half and a third of a cluster's cost is not attributable to any team's pods, and how you handle it determines whether people accept the report.
The shared pool includes the control plane fee, the system namespace, the CNI and CSI DaemonSets, monitoring and logging agents, the ingress controller and its load balancer, the service mesh if you run one, cluster autoscaler headroom, and the gap between what nodes cost and what pods requested.
Four ways to split it, in increasing order of how much argument they cause:
- Proportionally to each team's direct cost. Simple, defensible, and what we use by default.
- Evenly per team. Punishes small teams and starts a fight.
- By pod or namespace count. Rewards packing everything into one deployment.
- Left unallocated and owned by the platform. Honest, and it means nobody has an incentive to reduce it.
Whatever you choose, show it as a separate line rather than folding it in silently. A team that sees "your workloads: 4,100, share of platform: 900" accepts the second number. A team that sees one number 22 percent higher than they expected disputes the whole report.
Idle capacity deserves its own line too. If the cluster runs at 45 percent allocation, more than half the bill is headroom, and that is a platform finding, not a team finding.
Showback first, and for longer than you think
Showback means teams see their costs. Chargeback means the cost lands on their budget. Going straight to chargeback is the most common way this initiative dies.
The reason is that the first few months of numbers are wrong. Labels are missing, shared costs are modelled badly, a team gets attributed a workload it does not own, the discount is not applied. Every one of those is fixable, and every one of them is fatal to trust if it arrives attached to a budget line. Under showback, a wrong number is a bug report. Under chargeback, it is an accusation.
Run showback until teams stop disputing the numbers, which is usually a quarter or two. Then decide whether chargeback adds anything. In many organisations it does not: visibility plus a monthly conversation produces the behaviour change, and the internal accounting machinery is pure overhead.
What does work from the start is a weekly or monthly report that goes to the team, not to a dashboard they would have to visit. Include the trend, the requests-to-usage ratio, and the top three workloads by cost. Three numbers, in their channel.
Labels are the whole foundation
Allocation is only as good as the metadata. Decide a small, mandatory set of labels, and enforce them.
Owner, environment, cost centre and application is enough. Put them on namespaces and let workloads inherit, because per-pod labelling drifts immediately. Enforce with a policy in audit mode first, then warn, then require, exactly as described in Kyverno or Gatekeeper.
Track the percentage of cost that lands in "unallocated" as your headline quality metric. Above 10 percent, nobody trusts the report. Getting it under that is usually a fortnight of labelling work and it is the highest-value thing you can do before buying any tool.
Namespaces are the natural allocation boundary, which is one more reason to give each team its own, as in several teams on one cluster.
The things people forget
- Storage and network are missing from the naive model. Persistent volumes are attributable per claim. Cross-zone traffic usually is not, and it can be a large line.
- Spot and on-demand mix distorts comparison. Two teams with identical workloads pay differently if one landed on Spot nodes. Report the blended rate or explain the variance.
- Short-lived pods vanish. A CI job that runs for four minutes is real cost. Make sure your collection interval captures it.
- The recommendation is the point. Cost per namespace is a number; "your requests are 3.1x your usage, here is the corrected figure" is an action.
- Multi-cluster needs aggregation. Per-cluster reports do not tell a team what it spends overall, and teams usually span clusters.
What to do this week
Install OpenCost, wait a day, and pull cost by namespace alongside the requests-to-usage ratio for each. Do not show it to anyone yet. Look at the unallocated percentage first: that number tells you whether you have a cost problem or a labelling problem, and it is almost always the second one. We run this in the cost phase of a cloud engagement.