Scale sets averaging under 5% CPU with a measured off-hours window
What does ZopNight detect here?
An Azure VM Scale Set counts as idle when 30-day average CPU sits under 5%, memory utilization under 60%, and network under 1 MB/s average, with a full-window CPU peak veto that protects bursty nightly workloads. ZopNight then proposes a recurring off-hours schedule sized from the measured idle fraction, never a one-shot stop.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-270 |
| Category | schedule |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | vmss_idle.go |
Where it applies
Three quiet signals and one veto
CPU is the mandatory gate: the 30-day windowed average must sit below 5%, or nothing else is considered. Memory and network then act as suppressors evaluated over the full metric history. Available memory below 40% (meaning utilization above 60%) marks the set memory-bound, and average traffic above 1 MB/s on either direction marks it as serving; either cancels the finding. On top sits a full-window CPU peak veto: if the preserved series shows a spike above the safe ceiling, a recently-calm average cannot hide it, so a scale set that runs hot nightly batches is never labelled idle by a quiet fortnight.
The name-based threshold that had to go
An earlier revision raised the idle floor to 10% for scale sets whose names looked like AKS node pools, a name-substring classifier steering a scale-down recommendation. The override was removed in favour of the single conservative 5% floor for everything: a pool sitting at 5–10% CPU is now simply not flagged, which cannot create a false positive, whereas trusting names could.
Schedule as the only lever
A one-shot stop of a scale set is an indefinite outage, not a saving, so the rule’s category is schedule and its output is a recurring off-hours window. The dollar figure is monthly cost multiplied by the idle fraction measured from the aggregator’s usage heatmap, and the recommendation carries the start/stop cron pair, timezone, and heatmap. No measured idle fraction, or no positive pricing, means the rule abstains; it never emits a $0 advisory or a fabricated flat percentage.
Additional suppression gates
A scale set with a known active schedule is already parked deliberately and is skipped. A long-off set is also skipped, because scaling down an already-off fleet is redundant. Long-off means known uptime below the 5% floor, evaluated with enter/exit hysteresis bands so borderline sets don’t flip state between runs.
Inspect the scale set’s own CPU series
az monitor metrics list \ --resource $(az vmss show -g <rg> -n <vmss> --query id -o tsv) \ --metric "Percentage CPU" --interval PT1H \ --query "value[0].timeseries[0].data[].average" -o tsv | sort -n | tail -5Peaks under 5 across the tail corroborate the finding. Metrics need Monitoring Reader; applying the schedule uses the Zopnight Write Access custom role, which deallocates and restarts the set’s capacity on the recommended window.