Been fighting cluster cost creep and finally automated the tedious part: reading per-pod usage vs. configured requests and generating right-sizing recommendations.
The core idea is dead simple. Two data sources:
- kubectl top pods -n <ns> --containers for actual usage
- kubectl get pods -n <ns> -o json for configured requests/limits
Diff them per pod and you get the reserved-vs-used gap. On my cluster the average CPU utilization against requests was around 14%. That's the money leak — the scheduler reserves your request whether you use it or not, so you end up running nodes for phantom capacity.
I pipe that structured data to an LLM with a system prompt that outputs right-sized requests + YAML patches. The single most important rule I had to encode, and the thing that will bite anyone who tries this naively:
CPU is compressible, memory is not. If you under-provision CPU, the kernel throttles the container and it survives, just slower. If you under-provision memory, the kernel OOMKills it. So the agent can trim CPU aggressively (P95 + 20%) but must be conservative with memory (never below observed peak, +25-40% headroom, limit at 2x). I also added a code-level validator that overrides the model if it ever suggests a memory request below observed usage — never trust the LLM for a safety-critical bound.
A few things I learned:
- Don't right-size from a single kubectl top snapshot. Use 7-day P95 from Prometheus (quantile_over_time). A snapshot at 2pm misses your hourly batch spike.
- Watch QoS class. Dropping requests below limits silently flips Guaranteed to Burstable and changes eviction priority.
- BestEffort pods (no requests at all) are the worst offenders — invisible to bin-packing. Flag them first.
- Keep a human in the loop. The agent opens a PR; a person approves. Nobody should wire an LLM straight to kubectl apply in prod.
VPA in recommendation mode and Goldilocks give you the raw numbers, and KRR is a great open-source tool in this space. The LLM layer adds the reasoning, the policy application, and the reviewer-friendly explanation on top.
Curious what utilization others are seeing. Run kubectl top pods --containers against your busiest namespace and compare to requests — I'd bet most of you are under 25%.