Skip to main content
rightsizing · kubernetes

Workloads whose CPU request exceeds their observed 30-day peak

resource types
2
rule IDs covered
6
severity
medium

What does ZopNight detect here?

Reclaimable CPU is measured against the peak of the `CPUUsageMillicores` series over 30 days, never an average. ZopNight only recommends a resize when the reclaimable share falls between 5% and 85%. Outside that band the reading is treated as noise or as broken, and nothing is emitted.

Signal and threshold

How ZopNight evaluates Workloads whose CPU request exceeds their observed 30-day peak.
Field Value
Rule IDsRC-1770 · RC-1870 · RC-1970 · RC-1771 · RC-1871 · RC-1971
Categoryrightsizing
Severitymedium
Metricnone — pure configuration read
Sourceinternal/rules/k8s/cpu_over_provisioned.go

Sized against the peak, deliberately

The recommended request is the maximum observed value in the usage series, not a percentile and not a mean.

That is the conservative choice and it is intentional. Peak is always at least as large as p95, so a request resized to the peak still covers the busiest hour the workload actually had. The rule gives up some theoretical saving in exchange for never proposing a request that the observed history already exceeded.

The saving is per-pod cost × (request − peak) / request, and it is derived from the full metric’s peak rather than the 30-day window’s. A calm recent window must not be allowed to hide an older spike and talk the target down.

The 5%–85% band

Two guards bracket every recommendation.

Below 5% reclaimable, the number is inside the noise floor, and in practice a sub-5% reading is usually a stale or mismatched series rather than a genuinely well-sized workload. Nothing is emitted.

Above 85%, the request is either wildly mis-set or the usage series is empty or broken. A “reclaim 97% of your CPU” recommendation is far more likely to be a data fault than a finding, so that too is suppressed rather than shipped.

Why CPU and memory are treated differently here

CPU is compressible. A request trimmed below the working set causes throttling: the pod slows down, and the scheduler keeps it running. Recovery is a config change.

Memory is not. Trim a memory request below the real working set and the kernel OOM-kills the pod. That asymmetry is why the memory sibling of this rule abstains entirely today while this one emits, and it is a deliberate position rather than an implementation gap.

Five conditions that produce silence

Nothing is emitted unless all of these hold: the workload is running (not stopped, not degraded mid-rollout); a per-pod CPU request exists to reclaim against; a per-pod cost basis is available, so no zero-cost recommendation is ever produced; the CPUUsageMillicores series is present with sufficient coverage, not a point-in-time snapshot; and the peak is genuinely below the request.

metrics-server alone gives snapshots, not history. Clusters running only metrics-server will see this rule abstain across the board until a metrics pipeline retains a series.

Comparing CPU requests against kubectl top

Terminal window
kubectl get deploy -A -o json | jq -r '
.items[] | "\(.metadata.namespace)/\(.metadata.name)\t" +
([.spec.template.spec.containers[].resources.requests.cpu // "none"] | join(","))'
kubectl top pods -n <ns> --containers

kubectl top shows the instant, not the peak; treat it as a sanity check on the request, not as the basis for resizing.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

417 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

417 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·