Azure Cost Optimization
Key Points
- Mental model: ingress is free, egress is expensive. Same-region in-VNet traffic is free. Cross-region is metered. Internet egress is billable per GB.
- Idle resources are the silent budget killer: deallocated VMs still pay for disks; unused public IPs / gateways / Bastions tick 24/7.
- Reservations (1y/3y) and Savings Plans give 30–70% off compute. Spot VMs for evictable batch save 60–90%.
- Tag everything (
env,costCenter,owner,project) and enforce via Azure Policy. Untagged resources are unattributable. - Top three cost surprises: Log Analytics ingestion at full retention, Cosmos RU/s autoscale max, internet egress on chatty microservices.
Concepts (deep dive)
Azure cost optimization isn't one tool — it's a practice that compounds three habits:
- Don't pay for what nobody uses — kill idle resources, right-size oversized SKUs, tier cold data into cool/archive, decommission orphans.
- Commit where usage is predictable — Reservations and Savings Plans trade flexibility for 30–70% off the baseline you're running anyway.
- Architect with cost in mind — egress charges, cross-zone traffic, Log Analytics ingestion, and Cosmos RU/s aren't bugs to fix later; they're shape decisions you make on day one.
The rest of this file is the concrete levers under each habit. The order — mental model → Cost Management tooling → reservations/savings/spot → tagging/policy → service-specific traps — mirrors how a senior engineer audits an unfamiliar subscription.
The senior cost mental model
Free / cheap Expensive
───────────────────────────────── ──────────────────────────
Ingress to Azure Egress to internet ($/GB)
Same-region same-VNet traffic Cross-region traffic
Same-zone traffic Cross-zone (within region) — small fee
Reserved compute (-30 to -70%) On-demand compute
Spot VMs (-60 to -90%) Idle VMs paying full
Storage Cool / Archive tiers Hot tier for cold data
LRS GZRS, RA-GZRS
Log Analytics Basic Logs Analytics Logs at full retention
💡 The biggest cost mistake at senior level isn't picking the wrong SKU — it's not killing what nobody uses: dev environments running 24/7, ungoverned subscriptions, orphaned disks, public IPs detached from anything.
Azure Cost Management
Built-in (free) cost tooling:
- Cost analysis: pivot by service, resource group, tag, location.
- Budgets: monthly limits with email alerts at 50/80/100% — don't auto-stop services without explicit policy.
- Anomaly detection: ML-based; flags unusual cost spikes per resource group.
- Exports: daily CSV to Storage; ingest into Power BI for chargeback dashboards.
- Cost recommendations (via Advisor): right-size VMs, idle SQL DBs, unused public IPs, etc.
Reservations
Commit to compute capacity for 1 or 3 years; pay upfront or monthly.
| Resource | Discount range |
|---|---|
| VM (specific size + region) | 35–72% |
| App Service Plan (Premium v3) | ~40% |
| Azure SQL DB (vCore) | 30–55% |
| Cosmos DB (RU/s) | 20–63% |
| Storage (Blob committed capacity) | 13–38% |
⚠️ Reservations lock to specific size/region/family. Wrong fit = sunk cost. Use Reservation Recommendations in Cost Mgmt — based on 30-day usage.
Savings Plans (compute)
More flexible than reservations: - Commit $/hr for 1 or 3 years; applies to any VM size, any region (within compute family). - Slightly less discount than equivalent reservation, but survives architecture changes.
💡 Modern guidance: reservations for stable databases (SQL/Cosmos), Savings Plans for variable VM/App Service compute.
Spot VMs
- 60–90% discount vs on-demand.
- Azure can evict with 30s notice when capacity is needed.
--max-price -1means "pay up to on-demand price"; otherwise eviction also triggers when spot price exceeds your max.
✅ Use for: AI training, batch processing, Kubernetes preemptible node pools (AKS Spot pool), CI build agents. ❌ Don't use for: stateful primaries, customer-facing tier 1 services.
Dev/Test pricing
If your subscription is a Visual Studio / MSDN subscription, you get: - ~55% off Windows/SQL Server licensing on VMs. - No SQL Server licensing on Azure SQL DB Dev/Test tier. - Cheap test environments at ~half the cost.
Limitation: not for production workloads (license-side compliance).
Hybrid Benefit (BYOL)
If you own Windows Server / SQL Server licenses with Software Assurance: - Bring them to Azure VMs / Azure SQL. - Save the OS / SQL license cost (often 30–40% of VM hourly rate).
Eligible: Windows Server, SQL Server, Linux subscriptions (RHEL, SUSE).
Tagging strategy
Mandatory tags (enforce via Azure Policy):
costCenter = "8472"
env = "prod" | "staging" | "dev"
owner = "[email protected]"
project = "checkout"
Azure Policy (deny untagged):
Inheriting tags from RG to resources is not automatic — use a Modify-effect policy or a CI/CD step.
Right-sizing recommendations
Azure Advisor surfaces: - VMs with low CPU / network / IOPS for 14 days. - App Service Plans over-provisioned for the actual app traffic. - SQL DBs at <20% DTU/vCore utilization.
Workflow: Advisor → review → schedule resize during off-hours → monitor 7 days → finalize.
The forgotten resources tax
| Resource | Common waste |
|---|---|
| Managed disks | Detached after VM deletion; full price forever |
| Public IP Standard | Reserved but not assigned; ~$3/mo each, dozens accumulate |
| Application Gateway / Firewall / Bastion | $150–300/mo idle; abandoned demos |
| Snapshots | Old VM snapshots, never cleaned |
| Log Analytics workspace data | Default 31-day retention but you set 730; pays forever |
| Cosmos containers | Min 400 RU/s = ~$24/mo each, even with no traffic |
| Storage account snapshots/versions | Versioning ON without lifecycle = unbounded growth |
| Dev environments | Running 24/7 when only used 9–5 weekdays |
💡 Run a monthly orphan scan: detached disks, idle public IPs, empty resource groups, deallocated VMs older than 90 days.
Auto-shutdown for dev/test
resource autoShut 'Microsoft.DevTestLab/schedules@2018-09-15' = {
name: 'shutdown-computevm-${vm.name}'
properties: {
status: 'Enabled'
taskType: 'ComputeVmShutdownTask'
dailyRecurrence: { time: '1900' }
timeZoneId: 'Eastern Standard Time'
targetResourceId: vm.id
}
}
Saves ~50% on a 9–5 dev VM. Plus auto-start at 8 AM.
For App Service, use Always On = false + autoscale min 0 / 1 instance.
Cost surprises
Log Analytics ingestion
Default pricing tier: Pay-As-You-Go @ ~$2.76/GB ingested. A chatty diagnostic settings export can ingest TB/day.
✅ Tactics: - Basic Logs ($0.65/GB) for high-volume audit/firewall logs (limited query capability). - Sampling in Application Insights (default 100% — drop to 5–25%). - Filter on the agent: don't ship every Performance Counter. - Set table-level retention — keep 30 days for SecurityEvent, 7 for Heartbeat. - Use Data Collection Rules (DCR) to drop at ingestion. - Commitment tiers (>100 GB/day) save ~25%.
App Insights
- Default 100% sampling — for high traffic apps, drop to 5–10%.
telemetryConfiguration.DisableTelemetry = truefor noisy dependencies (Redis pings, health checks).
Cosmos DB RU/s
- Autoscale max can quietly hit ceiling and 10x cost.
- Min for a container = 400 RU/s = ~$24/mo even if empty.
- Serverless (≤5K RU/s, per-op) for sporadic workloads.
- Shared-throughput databases for many small containers.
Egress to internet
- $0.05–$0.087/GB depending on volume tier.
- Same-region same-VNet: free.
- Cross-region: $0.02–$0.05/GB.
- NAT Gateway data processing: $0.045/GB beyond included.
💡 Microservices doing 10s of GB/day cross-region for chat = $$$$. Co-locate in one region or use Front Door caching.
Bandwidth-heavy gotchas
- Container registry pulls across regions (use geo-replication or regional ACRs).
- AKS pulling from public Docker Hub instead of ACR.
- Backup egress to Recovery Services Vault in different region.
FinOps practices
- Chargeback model: every team sees their own cost; budget pressure where it can act.
- Cost ownership: each resource has a tagged owner; orphaned cost = team lead's lap.
- Weekly review: anomaly digest in Slack/Teams.
- Pre-deploy cost estimate: Bicep what-if + Azure Pricing Calculator in PR template.
- Showback for shared services: split central platform cost (firewall, log analytics) across consumers by usage.
Reserved Instances + Savings Plan combo
Use both: - Reservations on stable resources (production SQL, Cosmos primaries). - Savings Plan for compute breadth (App Service, dev VMs, AKS). - Spot for batch / training / CI.
A mature org typically has 60–80% of compute spend covered by some discount mechanism.
How it works under the hood
- Azure billing meters every API call / resource hour. Costs aggregate hourly into the billing system, available with ~8–24h delay in Cost Management.
- Reservations apply automatically when matching usage occurs in the scope (subscription / shared / management group).
- Anomaly detection uses Azure ML to model expected daily spend per RG; flags >2σ deviations.
- Cost exports run nightly into a Storage container; Power BI / Synapse can pull for dashboards.
Code: correct vs wrong
❌ Wrong: ungoverned tagging
✅ Correct: enforced tags
resource sa '...' = {
name: 'mystorage'
tags: {
env: 'prod'
costCenter: '8472'
owner: '[email protected]'
project: 'checkout'
}
}
❌ Wrong: full-fidelity App Insights at scale
✅ Correct: adaptive sampling
builder.Services.AddApplicationInsightsTelemetry(o =>
{
o.EnableAdaptiveSampling = true;
});
// Or fixed sampling:
// o.SamplingPercentage = 10;
❌ Wrong: max RU/s set defensively
Hits cost ceiling on a runaway query.
✅ Correct: tight max + alerting
Design patterns for this topic
Pattern 1 — "Tag-driven chargeback"
- Intent: every resource attributable; unowned resources eliminated.
Pattern 2 — "Reservation + Savings Plan + Spot stack"
- Intent: layer discount mechanisms; reach 60–80% covered compute.
Pattern 3 — "Lifecycle policies for storage"
- Intent: auto-tier hot → cool → archive → delete; never grow forever.
Pattern 4 — "Auto-shutdown for non-prod"
- Intent: turn off dev outside hours; save ~50%.
Pattern 5 — "Pre-deploy cost gate"
- Intent: PR template includes pricing calc; surprises caught before merge.
Pros & cons / trade-offs
| Aspect | Pros | Cons |
|---|---|---|
| Reservations | Big discount | Locked to size/region |
| Savings Plans | Flexible | Smaller discount |
| Spot VMs | Massive discount | Evictable; not for stateful |
| Hybrid Benefit | Use existing licenses | Must own SA |
| Dev/Test pricing | Cheap non-prod | Compliance limits |
| Cost Management | Built-in, free | Not real-time |
| Azure Advisor | Right-size hints | Conservative; verify |
| FinOps culture | Sustained savings | Org change effort |
When to use / when to avoid
- Use reservations on stable production primaries (SQL, Cosmos, App Service Plan core).
- Use Savings Plans for variable / migrating compute.
- Use Spot for CI agents, AI training, batch jobs.
- Use Cool/Cold/Archive tiers + lifecycle for any data >30 days.
- Avoid reservations on workloads you'll re-architect within a year.
- Avoid GRS/GZRS for ephemeral data.
- Avoid Hot tier as default for everything — measure access patterns.
Interview Q&A
Q1. Why is egress expensive but ingress free? Cloud economics: bringing data in is "good for the platform." Egress to internet is metered per GB.
Q2. Reservation vs Savings Plan? Reservations: lock to specific size/region, biggest discount. Savings Plans: $/hr commit, flexible across compute family, slightly less discount.
Q3. Spot VM use cases? Evictable workloads: batch, AI training, CI agents, AKS preemptible pools. 60–90% off.
Q4. Hybrid Benefit? BYOL — use existing Windows Server / SQL Server licenses with Software Assurance to skip Azure license cost.
Q5. Common idle costs? Detached disks, unattached public IPs, idle Bastion/AppGW/Firewall, dev VMs running 24/7.
Q6. Cosmos cost surprises? Autoscale max ceiling, min 400 RU/s per container, hot partitions inflating RUs.
Q7. Log Analytics savings? Basic Logs tier, sampling, table-level retention, commitment tiers, drop at ingestion via DCRs.
Q8. Tagging strategy? Mandatory: env, costCenter, owner, project. Enforce via Azure Policy deny.
Q9. Auto-shutdown for dev? DevTestLab schedule resource on VM; auto-stop at 7 PM, start at 8 AM. ~50% savings.
Q10. Application Insights cost? Default 100% sampling = expensive. Drop to adaptive or 5–10% for high-traffic apps.
Q11. Cost ownership? Tag every resource with owner; chargeback to team budgets; review weekly.
Q12. Cross-region traffic? Metered. Co-locate microservices in one region; use Front Door / regional caching.
Gotchas / common mistakes
- ⚠️ Untagged resources → unattributable cost.
- ⚠️ Default Log Analytics retention at 730 days for high-volume tables.
- ⚠️ Cosmos autoscale max too high → silent runaway spend.
- ⚠️ Reservation locked to wrong size when you plan to right-size.
- ⚠️ App Insights 100% sampling in prod high-traffic apps.
- ⚠️ Detached managed disks still billed monthly.
- ⚠️ Cross-region chatty microservices — egress + transit fees.
- ⚠️ Idle Bastion / AppGW / Firewall — $150–500/mo for nothing.
- ⚠️ No budget alerts — surprise at end-of-month invoice.