In a multitenant Kubernetes cluster, observability tells you a node is saturated or the cluster is overprovisioned. It does not tell you which tenant caused it, or what to change. That gap, between the symptom you can see and the tenant who is accountable is where both cost and responsibility can easily get lost.
This matters because almost nobody runs one cluster per team anymore. Once teams share a nodepool, what each workload reserves and what it actually uses start drifting apart. Your dashboards show the result. They do not show who owns it. This article walks through why that gap gets worse in shared clusters, why standard observability cannot close it, and what a real fix looks like for both platform and FinOps teams.
The two questions observability can't answer in a shared cluster
Open any Kubernetes monitoring dashboard and you can see plenty: CPU and memory usage per node, saturation, throttling, pressure. What you usually cannot see, fast, are the two questions that actually matter when something is wrong:
- Which tenant caused it?
- What needs to change?
And there is a lot to answer for. Datadog's research on containers found most workloads use less than 25% of the CPU they request, and less than half of the memory they request. Most of what a cluster reserves, and pays for, sits idle rather than running work. In a single-tenant cluster, that is just waste. In a multitenant cluster, it is also an accountability problem: the bill arrives as one number for the whole cluster, and nothing in it says which team's padding drove the spend.

This gap, between a saturated cluster and the tenant who caused it, is exactly what we work through live in our workshop, Operating Kubernetes Multitenancy, on 29 September. Save your seat
Requests vs actual usage: the gap that hides the cause
To see where the waste comes from, you have to look at two numbers per workload: what it requests, and what it actually uses.
A request is what a workload reserves. The scheduler places pods by their requests, quotas count them, and most cost tools bill on them too. Actual usage is what the container really consumes at runtime. In a healthy workload these two are close. In most real clusters they are not.
They drift apart because requests get set once and then forgotten: copied from another service, padded to be safe, inherited from a Helm chart default, and never revisited as the workload changed. Set them too high, and you reserve capacity nobody uses. Set them too low and the workload gets starved for CPU when the node is busy, or moves toward the front of the eviction line when the node runs short on memory. Either way, the request stops matching reality.
In a shared cluster, this can happen across many workloads at the same time. An underutilized node is not one bad workload. It is a requests-vs-usage mismatch across many tenants at once. Observability shows you the underutilized node. It does not show you which tenant's requests are the reason.
Why observability alone isn't enough for multitenancy
Standard monitoring shows you what is happening in your infrastructure, but it does not tell you which tenant owns the cost of it. In a shared cluster, this shows up in four ways:
It shows cost nowhere. You can see which pods are consuming what; that is exactly what cAdvisor and kubelet metrics are for. What they do not show is the cost of that usage, or which tenant owns it.
It shows usage, not the config gap. You see what a workload consumes, not that it reserved five times what it needs, which is the thing you would actually change.
It is node-centric, not tenant-centric. Node metrics blend every tenant on that node together. Pulling them apart by team means digging through labels by hand, and shared resources - a node, a database, the network - cannot be cleanly split by tenant at all.
It is reactive. You find out after the saturation, the throttling, or the eviction, not before.
There is a false tradeoff hiding under all this. Teams assume they have to pick between efficiency and accountability. Shared clusters and namespaces pack workloads tightly and improve utilization, but make it hard to see which tenant owns which slice of the cost. Giving each tenant its own cluster or even a dedicated nodepool, makes ownership clearer but adds management overhead and still leaves capacity stranded. You should not have to choose between the efficiency of multitenancy and knowing who owns the number.
Why Kubernetes' own boundaries don't close it
Kubernetes does give you tools to draw lines between tenants: namespaces, ResourceQuotas, and LimitRanges. They are good at controlling what a tenant can use. They are not built to tell you who is responsible for the cost.
A namespace can hold workloads from more than one team. Workloads move. A quota tells you the ceiling a tenant is allowed, and you can even check how much of it a namespace is using with kubectl describe resourcequota. But that is resource usage, not cost, and a namespace is not always one tenant. So these boundaries help you contain tenants, but on their own they do not map cleanly to cost ownership. That gap has to be filled another way.
What actually closes the gap: optimization and attribution
Closing the gap takes two different jobs, and it helps to keep them separate, because they work in different ways.
Optimization: right-size compute and memory to real usage. This answers "what to change." Continuously compare what each workload requests against what it actually uses, and turn the gap into a specific change: this workload can drop its CPU request, that one needs more memory. This is where PerfectScale works. It watches requests against real usage across the cluster and gives you the change to make, per workload, so underutilized nodes stop being underutilized. This part is measured in CPU and memory.
Attribution: tie the cost to the tenant who drove it. This answers "who," and it works differently from optimization. This is the part teams get wrong. Because tenants share nodes, you usually cannot cleanly split a node's CPU and memory between customers. There is no clean line on a shared node that says this much memory belongs to customer A and that much to customer B. So per-tenant cost attribution is usually based on a signal that stands for each tenant's real activity in the cluster: their share of HTTP request volume, the number of messages they produce and consume on a shared Kafka cluster, or another work indicator you can tie directly to a tenant. When a separate workload runs per tenant, you can attribute by that workload's own requests and usage instead. This is what Attribute™ by DoiT does: it reads that activity from the cluster's traffic and splits the shared cost across tenants by it, with no tagging project to maintain.
Keep the two straight. FinOps optimization is measured in compute and memory. Per-tenant attribution is measured by whatever best represents each tenant's activity in the cluster. Put them together and shared Kubernetes cost becomes something you can both reduce and account for: PerfectScale shows where the infrastructure can run more efficiently, and Attribute splits the shared bill across tenants by their activity .

What this means for platform and FinOps
The reason this gap is worth closing because two teams are stuck on the wrong side of it.
Platform gets a fast, trusted answer to "which tenant, and what do we change," instead of turning every saturation event into a search for the workload responsible across namespaces.
FinOps gets a per-tenant view of what each tenant cost to run and who can act on it, so chargeback and showback become a fact both sides can see, not a negotiation about whose workload it was.
That is the real payoff. You keep the efficiency of a shared cluster and you get the accountability of separate ones, without paying for separate ones.
Running multitenant Kubernetes with PerfectScale by DoiT
Shared clusters give you efficiency but hide ownership. Closing that gap by hand, across every tenant and every saturation event, does not hold up.
PerfectScale by DoiT is a resiliency-first Kubernetes optimization platform that continuously compares what your workloads request against what they actually use and turns the gap into right-sizing you can apply manually or automatically, so shared nodes stop carrying capacity no one uses, and so one tenant's padding does not become everyone's slow node and inflated bill. Paired with Attribute by DoiT, which splits each tenant's share of the shared cost by their activity, you get both sides of the multitenant problem: run the cluster efficiently, and know what each tenant costs to run. Teams like Paramount Pictures and Creditas run PerfectScale to keep shared clusters both efficient and reliable.
Sign up or book a technical session to see it on your own cluster.
Before you go: our workshop, Operating Kubernetes Multitenancy: Shared Cluster, Separate Headaches, is on 29 September at 11 AM ET, with Vikram Seshadri and Hili Paryenti from the Attribute team taking your questions live. Save your seat .