01 · Read the usage
Once a night, every container, 30 days back.
The metrics scan runs daily. For each metrics tenant, it asks for the
CPU and memory working set (the memory a container really uses).
It also asks for the configured requests, OOM kills and restarts.
It does this for every container in every namespace, over a
30-day window.
The assistant does not collect any data itself. It reads the
Prometheus or Mimir data you already have, read-only.
02 · Find the outliers
Only the containers worth a look go further.
A pre-filter picks the interesting ones. It always compares usage
with the request (the amount the container asks the cluster to reserve):
- average use under 30% of the request (it reserves too much),
- average, p95 or peak over 85% (it is about to hit the ceiling),
- any OOM kill or more than 3 restarts in the last day,
- no request at all, but real usage observed.
mimir-querier requests 5.6 GiB and uses about 64 MiB:
roughly 1% of what it reserves.
03 · Look at the shape
Average, p95 and peak, across all replicas.
An average hides bursts, so the sizing never rests on it alone.
For each container the assistant keeps the average, the 95th
percentile (p95) and the peak working set. It takes the highest
value across all 8 replicas that ran in the window.
Here the three numbers sit close together. The average is 64 MiB,
p95 is 76 MiB and the peak is 80 MiB.
04 · Classify
Flat or spiky? The answer changes the rule.
Volatility is peak divided by p95. At 1.25 or below, the
workload is flat. It has no real spikes. A big gap
between request and limit is then just reserved memory that nobody uses.
Above 1.25 it is spiky. A second number then decides how much
headroom to reserve. This number is namespace concurrency.
It shows if the pods around it peak at the same time or take turns.
The querier: 80 / 76 = 1.06, flat.
05 · Draft the change
The model proposes values, inside written rules.
The assistant sends the measured numbers, the classification and the
current manifest to the AI model. It also sends the sizing rules
for each case. The AI model returns a small structured proposal.
The proposal lists which values to change, and why.
The AI model may answer "keep as proposed". The goal is not to
tune for the sake of tuning.
06 · Clamp it
Code, not the model, has the last word on the numbers.
AI models sometimes ignore their own rules. So the code enforces
the hard limits again after the AI model answers:
- memory request never below the observed peak,
- memory limit never below the observed peak, never above five times it,
- no more than a 5× gap between request and limit,
- requests never above limits,
- CPU limits removed. CPU is throttled, not killed, so a CPU limit only adds latency.
Here the AI model suggested a 64 MiB request. That is below the
80 MiB peak, so the code raised it.
07 · Write the smallest diff
Only the resource values move.
The assistant writes the change back into the file in place. Comments,
key order and every other value stay exactly as they were.
It rounds values up to standard steps (64, 96, 128 MiB…),
never down.
For a HelmRelease (a Flux object that installs a Helm chart), the edit goes into
spec.values. The chart reads its values from there. The edit does not go into rendered output.
08 · The proposal
The evidence travels with the change.
Every MR that touches resources carries the measurements it used for sizing.
These are the classification, volatility, namespace concurrency,
average, p95 and peak. They also include how many replicas the assistant observed
and which safety clamps fired. You can check the arithmetic without opening
Grafana.