Running Azure VMs averaging under 5% CPU for 30 days, with the right fix for each
What does ZopNight detect here?
Azure VMs that stay running at under 5% `Percentage CPU` for 30 days bill full compute for almost no work. ZopNight checks memory and network activity too, then proposes one of three fixes: a recurring off-hours schedule, a review-then-deallocate for VMs idle in 95% of hours, or a smaller size when a reservation covers the VM.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-201 |
| Category | idle |
| Severity | medium |
| Metric | Percentage CPU |
| Threshold | average below 5% |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | Microsoft.Compute/virtualMachines/read · Microsoft.Insights/Metrics/Read |
Where it applies
Idle compute is billed exactly like busy compute
Azure bills a VM in the Running state for its full size. Microsoft’s VM states and billing table marks Running and Stopped (allocated) as billed and Deallocated as not billed, with the caveat that disks and networking keep charging. A VM that averages a few percent CPU all month costs the same compute as one at 80%.
Finding low-CPU VMs from the CLI
List the running VMs, then pull a month of hourly CPU, memory and network for a candidate:
az vm list -d \ --query "[?powerState=='VM running'].{name:name, group:resourceGroup, size:hardwareProfile.vmSize}" -o table
az monitor metrics list \ --resource /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<vm> \ --metric "Percentage CPU" "Available Memory Percentage" "Network In Total" "Network Out Total" \ --aggregation Average Maximum --interval PT1H --offset 30dGuards a VM must pass to count as idle
- The VM is running, and no known active schedule already parks it. VMs that ZopNight has measured as mostly off are also left alone.
- Average
Percentage CPUover the last 30 days is below 5%. - Memory is not the bottleneck: if available memory averages below 40% (more than 60% used), the VM is treated as a memory-bound workload such as a database or cache.
- Network is quiet: an average above 1 MB per sample on either
Network In TotalorNetwork Out Totalsuggests a proxy, gateway or replication target, and the VM is skipped. - The VM has a positive monthly price.
Which fix you get, and when there is none
- Reservation or savings plan coverage: deallocating does not refund a one- or three-year commitment, so the proposal is a smaller size, priced from real rates. No smaller size or no rate means no finding.
- Idle in at least 95% of hours: measured from the VM’s own hourly CPU over at least 7 days of samples, this becomes a review-then-deallocate advisory. It is vetoed when a peak of 80% CPU recurs in most observed weeks (a scheduled job), when CPU reaches 30% in at least 5% of hours (routine short work), or when the name suggests a bastion, jump box, VPN, HA or DR node, or a stateful data service.
- Everything else: a recurring off-hours schedule. With no measured idle share there is no finding, never a flat estimate. Dev and test schedules are also covered by Azure VM Non-Production Scheduling.
How each proposal is priced
schedule: saving = monthly cost x measured idle share of hoursreview-deallocate: saving = compute portion only (managed disks keep billing)smaller size: saving = VM monthly cost x (1 - smaller size rate / current size rate)For a VM under a reservation or savings plan, the commitment keeps billing after the resize, so this saving is realised only when other VMs use the freed commitment (for example through reservation instance size flexibility) or the reservation is exchanged.
Acting on an idle VM
- Review CPU, memory and network in Azure Monitor and confirm with the owner that nothing depends on the VM around the clock.
- For the schedule proposal, set start and stop times rather than leaving the VM off for good.
az vm auto-shutdown -g <rg> -n <vm> --time 1900covers the nightly stop. - For the deallocate review, run
az vm deallocate -g <rg> -n <vm>once the owner agrees. - For a VM covered by a reservation, resize with
az vm resize -g <rg> -n <vm> --size <smaller-size>and review the commitment with whoever owns reservations, since the smaller VM may no longer match the reserved size.