Node pools a full machine-type rung larger than their CPU needs
What does ZopNight detect here?
Every rung on the GCE ladder doubles vCPU, so halving a node pool's machine type roughly doubles its utilization. ZopNight therefore requires average node CPU under 50% and a trusted peak also under 50% before proposing the next-smaller same-family type, executed as a guided rolling node recreate.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1228 |
| Category | rightsizing |
| Severity | low |
| Metric | none — pure configuration read |
| Source | gke_pool_rightsize.go |
Where it applies
A 2x step needs a 50% ceiling
GCE machine families step in powers of two (n1-standard-4 to n1-standard-2 halves the vCPUs), so a pool moved one rung down runs at roughly double its previous utilization. The generic 80% peak guard used by one-tier downsizes is dangerous here: a pool peaking at 79% would land near 158% and throttle every pod on it. Both gates in this rule therefore sit at 50%: the 30-day average must be below it to fire, and the peak must be below it to survive the guard, preserving about 2x headroom through the halving.
Trusted peaks only
The peak check refuses thin evidence. A maximum is only a true hourly peak once the series carries at least 7 days of max-band coverage; below that it is a smoothed peak-of-averages that systematically understates spikes. That data is biased toward exactly the mistake the guard prevents. A young or sparsely-monitored pool fails closed. Rates for the current and target machine types come from the live pricing catalog, and the saving is cost × (current − target) ÷ current; a missing or inverted rate kills the recommendation rather than shipping $0.
The rolling recreate and its blast radius
Applying the change is one API call: GKE’s UpdateNodePool with the smaller machine type,
which ZopNight’s provisioner drives under the catalogued container.clusters.update
permission in roles/container.clusterAdmin. GKE then drains and recreates each node in
turn. That rolling recreate evicts every pod on the pool, which is why the remediation is
a guided wizard with a PodDisruptionBudget check in front of it rather than a silent
auto-fix.
Read the pool’s machine type
gcloud container node-pools describe my-pool --cluster my-cluster \ --location us-central1 --format="value(config.machineType)"Watch application latency for a day after the migration; the halved pool should settle near double its old utilization, not at saturation.
Families, customs, and floors
Custom shapes, shared-core types, GPU rungs, legacy families, and pools already at the bottom of their ladder have no next-smaller target and never fire. Every emission names a concrete catalog machine type; “use something smaller” is not a recommendation this rule will make.