# Idle Azure VM Scale Set

> 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.

Source: https://zop.dev/integrations/azure/recommendations/idle-azure-vm-scale-set
Updated: 2026-08-19

---

## 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

```bash
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 -5
```

Peaks 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.
