Non-production VMs consuming reservation or savings plan hours that Spot could replace
What does ZopNight detect here?
ZopNight flags a dev or test VM, not recorded as Windows, that is covered by a reservation or savings plan when the same size's Spot rate is cheaper than its 1-year reserved rate. Moving that VM to `--priority Spot` frees the committed hours for production usage, and ZopNight prices the gap as 1 minus Spot over reserved.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1381 |
| Category | discount |
| Severity | medium |
| Metric | Percentage CPU, Network In Total (evidence only) |
| Threshold | covered by a commitment, positive non-production signal |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | Microsoft.Compute/virtualMachines/read · Microsoft.Capacity/reservationorders/reservations/read |
Where it applies
Why a reserved dev VM can still be overpaying
A reservation makes a VM cheaper than pay-as-you-go, but for a workload that tolerates being interrupted it is not the cheapest option. Azure Spot VMs run on spare capacity at a variable price, with no SLA and eviction on 30 seconds’ notice. Microsoft names dev/test environments and batch jobs as good fits.
There is a second benefit. Reservation discounts float to any matching VM in scope, so when a dev VM stops consuming reserved hours, those hours can cover a production VM that is currently paying full price.
Spotting dev and test VMs under a commitment
A name filter gives a first list; confirm coverage in the portal under Reservations or in the reservation’s utilization report:
az vm list \ --query "[?priority!='Spot' && (contains(name,'dev') || contains(name,'test'))].{name:name, rg:resourceGroup, size:hardwareProfile.vmSize}" \ -o tableConditions ZopNight checks
- ZopNight’s billing data shows the VM covered by a reservation or savings plan. Pay-as-you-go VMs belong to Azure Spot VM Opportunity.
- The VM is not already Spot or low priority.
- A positive non-production signal: a dev or test environment tag, or a dev/test name, with no production environment tag.
- The operating system is not recorded as Windows or SQL Server.
- It is not an M-series VM, a Databricks-managed VM or a scale set member.
- Its name does not suggest a data store (database, Kafka, Elasticsearch, Redis and similar) or a
standby role such as
dr,standby,failoverorreplica.
CPU and inbound network over 30 days are shown as context only.
Where the migration is not suggested
The operating system check only excludes VMs recorded as Windows or SQL Server; a VM with no OS recorded is not excluded on that ground, so confirm the OS before acting. Missing Spot or 1-year reserved rates for the size, or a zero cost, also mean no finding, since ZopNight will not assume a typical Spot discount. One known gap: a member of a Flexible orchestration scale set can look like a standalone VM and may still be listed.
Spot priced against the reserved rate, not list price
discount = 1 - (Spot hourly rate / 1-year no-upfront reserved hourly rate)saving = current monthly VM cost x discountThe denominator is the reserved rate because the VM’s current cost is already discounted by the commitment. Comparing Spot with pay-as-you-go would overstate the gain. Discounts outside a 5% to 92% band are treated as bad rate data.
Moving the VM to Spot
- Confirm the workload handles eviction;
az vm simulate-eviction --resource-group my-rg --name my-spot-vmlets you test that on a Spot copy. - Recreate it as Spot, for example
az vm create ... --priority Spot --max-price -1 --eviction-policy Deallocate, from a snapshot or image of the current disk. - Delete the original VM once the Spot copy is serving.
- Check that the reservation’s utilization stays high; if nothing else in scope uses the freed hours, widen its scope or plan an exchange.