Run Kubernetes at any meaningful scale and your cluster is almost certainly burning money. By a significant margin. The number most teams find when they look is somewhere between 50% and 70% waste. For a company spending a million dollars a year on Kubernetes, that's five to seven hundred thousand dollars going somewhere it shouldn't. Every year.
That sounds like deliberate failure. It isn't. Nobody sets out to build a wasteful cluster. The waste is the predictable, almost inevitable byproduct of how engineering teams operate Kubernetes day-to-day. Once you see why it happens, the fix becomes obvious. So does why most "optimisation" tools haven't fixed it.
Where the waste comes from
Consider what happens. An engineer ships a new microservice. Before it goes live, they have to fill in two numbers in the YAML: a resource request (the minimum CPU and memory the cluster guarantees the pod) and a resource limit (the cap before things get throttled or killed). These numbers control how the scheduler places pods, how much capacity gets provisioned, and what your cloud provider charges you.
Those numbers are guesses. The engineer doesn't have a month of production traffic to calibrate against, so they estimate. Getting it wrong on the low side is loud: pods get throttled, services OOM-kill, customers see errors, somebody pages you at 2am. Getting it wrong on the high side is silent. The bill grows quietly, and nobody notices.
So engineers default high. Two times the actual need is common. Three times is normal. Five times happens more than people expect. Then the workload ships, the engineer moves on, and those numbers go invisible. Nobody comes back a month later to check them. Nobody revisits them after traffic patterns settle. They sit there. Forever.
What stands out is that nobody is being negligent here. Engineers over-provision because the operational logic is sound. The cost of throttling is immediate and visible. The cost of waste is buried in next month's cloud bill, which somebody else reviews, often weeks later. Rational behaviour at the individual level. Disastrous at the cluster level.
Why one bad number per pod becomes a cluster-wide problem
The financial damage isn't linear. It compounds. Walk through what happens in a cluster running a few hundred microservices.
Pods request more than they need. The Kubernetes scheduler treats those requests as real and refuses to pack more pods onto a node than the requests allow. Even if real usage is a third of what's been claimed, the scheduler sees "full." More workloads come in. The cluster autoscaler spins up new nodes. Those new nodes also fill up with over-provisioned pods. The cluster grows. The bill grows. The actual computational throughput per dollar drops.
Each layer compounds the one above it. By the time the bill arrives, you're paying for two clusters' worth of capacity to do one cluster's worth of work.
The cumulative effect is that the company is paying for two clusters' worth of capacity to do one cluster's worth of work. And because it's distributed across thousands of YAML files written by dozens of engineers over months or years, no single person has the authority or the time to fix it.
The three fixes everyone tries. And why they don't work.
When engineering leaders see the numbers for the first time, they reach for one of three solutions. None of them resolve the underlying problem. Worth understanding why.
Manual rightsizing
The most obvious answer: assign someone to go through every workload and set the request and limit numbers correctly. This works in theory and almost never works in practice. A typical cluster has hundreds of workloads, each with bursty traffic, dependency-driven memory patterns, and SLO requirements that vary by application tier. Sizing each one is a multi-week project. And the moment you finish, the workloads have changed, the traffic has shifted, and your numbers are stale.
Rightsizing is a continuous problem, not a project. Manual approaches treat it as a project. That's why every team that tries this gives up around week three.
The Kubernetes Vertical Pod Autoscaler (VPA)
Kubernetes ships with a built-in tool that's supposed to solve this: VPA. In principle, it continuously analyses pod usage and adjusts requests automatically. In practice, fewer than 1% of organisations run VPA in full automation in production. The reasons are technical and they're not subtle:
- VPA evicts pods to apply resource changes. That's a service disruption every time it acts. Unacceptable for production workloads.
- The recommendation algorithm uses an 8-day decaying histogram. Yesterday's traffic carries 50% weight. Four-day-old data carries 6%. By definition, VPA lags real traffic patterns badly.
- It can't distinguish workload types. The same algorithm runs on a stateless API, a database, and a batch job. Predictably bad results in at least two of those three.
- It conflicts with HPA. Most teams running horizontal scaling can't enable VPA without breaking the autoscaler they depend on.
So VPA usually gets deployed in recommendation-only mode, and the recommendations sit untouched because nobody trusts them enough to apply.
FinOps dashboards
The third path is buying a FinOps tool to surface waste across the cluster. These tools are excellent at one job: telling you where the waste is. Detailed cost breakdowns by team, namespace, workload. Reports for finance. Anomaly alerts.
The gap is simple: visibility isn't savings. A typical FinOps dashboard generates dozens to hundreds of optimisation recommendations every quarter, and most never get implemented. Engineering teams don't have the bandwidth to manually rightsize 400 pods, and the recommendations often lack the workload context engineers need to trust them. The dashboard surfaces the problem, the team agrees the problem is real, the cluster keeps wasting money.
We've written about this gap in more detail in our comparison of OptOps.ai vs FinOps dashboards if you want the deeper version.
| What you need | Manual | VPA | FinOps Dashboards | OptOps.ai |
|---|---|---|---|---|
| Workload-aware | ~ Engineer-dependent | ✕ Generic algorithm | ~ Static thresholds | ✓ Learns over time |
| Production-safe | ✓ Manual approval | ✕ Evicts pods | ✓ Read-only | ✓ Read-only by default |
| Scales beyond a few workloads | ✕ Time-bound | ✓ Automated | ✓ Cluster-wide | ✓ Cluster-wide |
| Closes the loop to action | ✓ If you have time | ~ If you trust eviction | ✕ Recommendations sit unused | ✓ Through your CI/CD |
Each approach solves part of the problem. Only one solves all four parts at once.
Manual rightsizing produces accurate fixes but doesn't scale. VPA scales but isn't safe enough for production. Dashboards produce visibility but no action. Each fixes part of the loop. None close it.
What works
The reason over-provisioning persists isn't that engineering teams are careless. It's that solving it requires three things at once, and no existing tool delivers all three:
- Workload-aware intelligence. Recommendations sized to the specific traffic, burst, and SLO patterns of each workload. Not generic algorithms applied uniformly across stateless APIs, stateful databases, and batch jobs.
- Production safety. Read-only operation by default. No third-party process taking write actions on critical clusters without explicit approval. SREs keep accountability. Engineers keep visibility.
- An action layer. A way to apply the recommendations through engineering's existing CI/CD and approval workflows, so changes don't sit in a backlog forever.
This is the gap OptOps.ai was built to close. The architecture is deliberately advisory-first: read-only collection at install, metadata-only (no secrets transmitted), no write access required. The AI continuously analyses workload behaviour and surfaces precise, sized recommendations, pod by pod, with ROI estimates attached. Engineers apply changes through their own CI/CD, with full visibility into what's being changed and why. The cluster gets leaner. The savings are real. The team stays in control.
What to do this week
If you haven't recently checked your cluster's actual utilisation against its provisioned capacity, the first move costs nothing and takes about an hour. Pull a snapshot of average CPU and memory utilisation across the cluster over the last 30 days. Compare it against average resource requests. The gap between those two numbers is your waste. In real percentage terms.
Most teams who do this are surprised. The number isn't 10% or 15%. It's usually 50% or higher. Once you see your own number, the question stops being "is this real" and becomes "what's the safest path to fix it."

