Node pools peaking under 20% CPU and 30% memory
What does ZopNight detect here?
GKE node pools whose peak CPU stays under 20% and peak memory under 30% for the whole window are over-provisioned on both axes. ZopNight prices consolidation onto the next-smaller machine type in the same family from live SKU rates, though per-pool cost is deliberately zero today to avoid double-counting member VMs.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-121 |
| Category | rightsizing |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | gke_underutilized_nodes.go |
Where it applies
Peaks on both axes, not averages
An average hides the moment that matters. This rule gates on the maximum of both
allocatable-utilization series over the window: node CPU must peak under 20% and node
memory under 30% simultaneously. A pool that ever spiked past either ceiling is left
alone, because the spike is exactly the capacity claim a consolidation would break. Both
series are the kubernetes.io allocatable-utilization metrics, scaled to percent and read
per pool through monitoring.timeSeries.list (roles/monitoring.viewer).
Stricter sibling of the CPU-only rule
RC-1228 downsizes pools on a 50% CPU average alone. This rule is its conservative subset: both axes, peak-based, and much lower ceilings. What it buys with that strictness is confidence that the pool is not merely CPU-quiet but genuinely small on every dimension. That is the shape you get from a pool built for a workload that has since moved away. The lever and the arithmetic match the sibling: the next-smaller machine type in the same GCE family, priced as cost × (current rate − target rate) ÷ current rate from live catalog rates, and abstaining whenever the ladder has no smaller rung or either rate is missing.
Why pools carry no cost of their own
ZopNight prices GKE nodes as the individual Compute Engine VMs they are; giving the pool a price too would count the same machines twice. Per-pool cost is therefore zero by design in the calculated path, which keeps this rule’s dollar figure gated off on live fleets. Node savings surface today through the per-VM rightsizing rules instead, while this detection logic stands ready should a per-pool cost basis land.
Sample node utilization
gcloud container node-pools describe my-pool --cluster my-cluster \ --location us-central1 --format="value(config.machineType,initialNodeCount)"Pair the machine type with the Kubernetes Engine → Nodes utilization charts over 30 days before acting.
The consolidation path
Confirm aggregate pool pressure and PodDisruptionBudgets, enable the cluster autoscaler so emptied nodes actually leave, and lower the pool minimum. The rule never emits on missing metrics, an unparseable or floor machine type, or absent rates. Silence beats a guessed downsize.