
The legacy platform handled millions of transactions a day. Over 13 months of monitoring data, its monthly peak CPU was 69.4%. Its monthly averages sat between 1.6% and 6.7%.
That was the most useful number I found while assessing a new Kubernetes platform that was about to replace it. Not because it told me how many cores to buy. Because it told me CPU was the wrong thing to size on.
The new platform was a few months from launch, with seasonal traffic peaks ahead. I was asked to assess whether it was ready and what it needed. The obvious capacity question is "how much compute do we need for launch day?", and the obvious way to answer it is to look at the old system's CPU and scale it up.
If I'd done that, I would have concluded the new platform had plenty of headroom. The old one barely used its CPUs. Two fixed nodes in the new cluster looked fine by that logic.
The trouble is that the old platform was never CPU-bound. Something else set its ceiling. A new platform sized on CPU inherits the wrong mental model, and it fails somewhere nobody is watching.
I read the code before I had cloud access: the infrastructure repositories in full, plus what monitoring and the delivery tooling could show me. That gave me a different picture.
Every production service ran as a single replica. One small managed database instance held 9 databases behind a max_connections of 200, with no connection pooler in front of it.
Now do the arithmetic the CPU graph hides. Say you look at launch traffic and decide to scale every service from 1 replica to 3. Each replica opens its own connection pool. More than a dozen services, each with a pool of 10 or 20 connections, times 3. You're past 200 before the first real user arrives. The database starts refusing connections, the services start failing health checks, and the autoscaler, if there is one, adds more replicas that open more connections.
That's the failure mode a CPU-based plan walks straight into. The fix is in the wrong order if you're not careful: add the pooler first, then add replicas.
For a web platform with a shared database, these tell me more than CPU does:
CPU still matters. I just treat it as the last thing to check, not the first.
One more thing from this assessment. Some of what I'd been told verbally didn't match the code. One component described as self-hosted was a hosted service. The team said there was no observability stack; Terraform said there was a full one, just with no alerts or dashboards wired up.
Neither was anyone hiding anything. People describe the system they remember, and systems drift from that. When I assess a platform now, I mark each finding with where it came from. "Terraform declares this" is not the same as "this is running", and "the team said" is not the same as either.
It wasn't all gaps, and an assessment that only lists problems isn't useful. Passwords never entered Terraform state, because the code used write-only arguments. There was a promotion gate that refused to deploy a version to production unless it had already been in test. Nothing deployed the latest tag. Those are the habits that make the rest fixable.
I'd ask for the old platform's monitoring data on day one, before reading any code. Thirteen months of real traffic is the best capacity document you'll ever get. Once I saw single-digit CPU averages next to millions of daily transactions, the rest of the assessment reorganised itself around the database.
I'd also write the connection arithmetic into the findings as a table: services, replicas, pool size, total, limit. A table like that ends the "just add replicas" conversation faster than any paragraph.
If you're about to launch a new platform and want a second look at where it will break first, I do that kind of assessment. See Kubernetes & Platform.
Spot nodes were reclaimed, the on-demand fallback hit its own limit, and production was down for about 25 minutes. Then I moved production off spot.
A production rollout sat blocked for 8 days while the site looked healthy. The first week of real alerts found it, and stuck queue messages too.
A CPU request far below real use made the HPA scale up and down every 1 to 2 minutes, and users got hard refreshes. Raising one number fixed it.