An estate-wide Azure cost review where every finding was validated against live state before it reached leadership
Cost dashboards were full of "potential savings", but many of them were stale or wrong. Resources were already compliant, already stopped or still needed. I ran an estate-wide review and only reported what I'd checked against live resource state. The result was a prioritised plan worth a five-figure sum every month, including quick wins that could be actioned straight away with no risk.
| Priority | Finding | Share of savings | Risk |
|---|---|---|---|
| 1 | Non-production compute running 24/7: more than a dozen AKS clusters plus several VMs | Largest (more than half) | Low, with opt-out tags |
| 2 | Idle managed workflow schedulers in dev and test | Large | Low |
| 3 | Licence benefit not applied to eligible production VMs | Small | None (quick win) |
| 4 | Orphaned storage: a multi-terabyte snapshot set and an unattached premium disk | Small | Confirm with the owner first |
resources
| where type =~ 'microsoft.compute/disks'
| where properties.diskState =~ 'Unattached'
| project name, resourceGroup, sku = sku.name,
sizeGB = toint(properties.diskSizeGB), created = properties.timeCreated
| order by sizeGB desc
AKS clusters can't stop themselves, and an in-cluster CronJob can't start the cluster it stopped. So I recommended an external schedule, with opt-in by tag so teams stay in control:
schedules:
- cron: "0 20 * * 1-5"
branches: { include: [ main ] }
always: true
steps:
- task: AzureCLI@2
inputs:
azureSubscription: nonprod-automation
scriptType: bash
inlineScript: |
az aks list --query "[?tags.autoshutdown=='true'].[name,resourceGroup]" -o tsv |
while read -r name rg; do az aks stop -n "$name" -g "$rg" --no-wait; done
The biggest saving wasn't exotic. It was switching things off when nobody uses them. The value was in the evidence behind each line.
About this case study: this write-up is drawn from my hands-on platform engineering experience. Organisation names, system names, figures and timelines have been changed or generalised, and all code, configuration and queries are illustrative examples written for this page.