Skip to main content
Azure · lesson 10 of 10
Azure advanced Lesson 10 of 10

Also part of: Multi-Cloud

Azure Cost Management Basics

Break down spend with az costmanagement, weigh real pay-as-you-go vs. reserved instance pricing for one VM size, and skim the Well-Architected cost pillar.

By SkillByExample · Updated

azure cost-management finops well-architected-framework

Cost Management answers “what did we spend and on what,” reservations and the Well-Architected Framework’s cost pillar answer “how do we spend less without breaking something else.” All three matter together — cutting cost without reading the trade-off is how a Well-Architected review finds an over-optimized deployment months later.

Reading a cost breakdown

az costmanagement query \
  --type ActualCost \
  --timeframe MonthToDate \
  --scope "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33" \
  --dataset-aggregation '{"totalCost":{"name":"PreTaxCost","function":"Sum"}}' \
  --dataset-grouping name="ResourceGroup" type="Dimension" \
  --output table
$ az costmanagement query --type ActualCost --timeframe MonthToDate --scope "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33" --dataset-aggregation '{"totalCost":{"name":"PreTaxCost","function":"Sum"}}' --dataset-grouping name="ResourceGroup" type="Dimension" --output table
PreTaxCost    ResourceGroup    Currency
------------  ---------------  ----------
14.82         learn-rg         USD
2.03          NetworkWatcherRG  USD

NetworkWatcherRG is a resource group Azure creates automatically the first time Network Watcher is used in a region (triggered by the test-ip-flow call in the virtual-network lesson) — a common source of “where did this resource group come from” confusion in a cost report.

A real pay-as-you-go vs. reserved instance comparison

Rather than quoting a discount percentage from memory, pull actual current prices from Azure’s public Retail Prices API for one concrete SKU — Standard_D2s_v5 (2 vCPU, 8 GiB), Linux, East US:

curl -s "https://prices.azure.com/api/retail/prices?\$filter=armRegionName eq 'eastus' and armSkuName eq 'Standard_D2s_v5' and priceType eq 'Consumption'" \
  | jq '.Items[] | select(.productName=="Virtual Machines Dsv5 Series") | {meterName, retailPrice, unitOfMeasure}'
$ curl -s "https://prices.azure.com/api/retail/prices?..." | jq '...'
{
  "meterName": "D2s v5",
  "retailPrice": 0.096,
  "unitOfMeasure": "1 Hour"
}
curl -s "https://prices.azure.com/api/retail/prices?\$filter=armRegionName eq 'eastus' and armSkuName eq 'Standard_D2s_v5' and priceType eq 'Reservation'" \
  | jq '.Items[] | {reservationTerm, retailPrice}'
$ curl -s "https://prices.azure.com/api/retail/prices?..." | jq '...'
{ "reservationTerm": "1 Year", "retailPrice": 519.0 }
{ "reservationTerm": "3 Years", "retailPrice": 997.0 }

Fetched from Azure’s live Retail Prices API on 2026-09-13, region eastus, SKU Standard_D2s_v5. The reservation retailPrice is the total cost for the whole term, paid upfront — not a per-hour rate — so the comparison needs converting to the same unit:

Purchase optionTotal costEffective hourlyvs. pay-as-you-go
Pay-as-you-go$0.096/hr × 8,760 hr/yr = $840.96/yr$0.0960—
1-Year Reserved$519.00 for the year$0.059238.3% cheaper
3-Year Reserved$997.00 for 3 years ($332.33/yr)$0.037960.5% cheaper

(8,760 = 24 × 365 hours/year; savings = (840.96 − annualized_reserved) / 840.96.)

The 3-year number looks like the obvious choice, but the trade-off is commitment: a reserved instance bills its full amount whether or not the VM runs, so it only pays off if the workload is genuinely steady for the term. A workload that might be decommissioned in eight months should stay on pay-as-you-go even at the worse hourly rate — this is exactly the kind of cost-vs-flexibility trade-off the Well-Architected Framework’s cost pillar asks you to state explicitly rather than defaulting to “cheapest number.”

The Well-Architected Framework’s five pillars, at a glance

PillarCentral questionWhere it showed up in this track
ReliabilityDoes it recover from failure?Automatic backups in the Azure SQL lesson
SecurityIs access no broader than needed?Scoped RBAC role assignments in the Entra ID lesson
Cost OptimizationAre you paying for what you use?This lesson’s PAYG-vs-reserved comparison
Operational ExcellenceCan you observe and operate it?Metrics, KQL, and alerts in the Azure Monitor lesson
Performance EfficiencyDoes it meet load without over-provisioning?VM sizing (Standard_B1s vs Standard_D2s_v5)

The framework’s own point is that these pillars pull against each other: a 3-year reservation improves Cost Optimization but reduces the flexibility that Performance Efficiency wants when load patterns change, and locking RBAC down tightly (Security) can slow down Operational Excellence if every routine task needs a new role request. A Well-Architected review names the trade-off being made, rather than treating one pillar as free to maximize.

Practice

1. Break down the same month's cost by service instead of by resource group.
az costmanagement query --type ActualCost --timeframe MonthToDate --scope "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33" --dataset-aggregation '{"totalCost":{"name":"PreTaxCost","function":"Sum"}}' --dataset-grouping name="ServiceName" type="Dimension" --output table
$ az costmanagement query ... --dataset-grouping name="ServiceName" type="Dimension" --output table
PreTaxCost    ServiceName          Currency
------------  -------------------  ----------
9.14          Virtual Machines     USD
4.02          Storage              USD
2.31          SQL Database         USD
1.38          Azure Monitor        USD

Same query, different --dataset-grouping dimension — cost analysis is one query engine with the breakdown dimension as a parameter, not a separate report per view.

2. Create a budget that alerts at 80% of a $50 monthly threshold.
az consumption budget create \
  --budget-name learn-monthly-budget \
  --amount 50 \
  --time-grain Monthly \
  --start-date 2026-09-01 \
  --end-date 2027-09-01 \
  --notifications '{"actual_GreaterThan_80_Percent":{"enabled":true,"operator":"GreaterThan","threshold":80,"contactEmails":["reader@example.com"]}}'
$ az consumption budget create --budget-name learn-monthly-budget --amount 50 --time-grain Monthly ...
{
  "name": "learn-monthly-budget",
  "amount": 50.0,
  "timeGrain": "Monthly",
  "category": "Cost"
}

Cost analysis only reports after the fact; a budget is the piece that proactively emails before a resource group runs away with spend, which matters most in a lesson environment where a forgotten VM is easy to leave running.

3. Pull pay-as-you-go pricing for the B1s size used in the VM lesson and compare it to D2s_v5.
curl -s "https://prices.azure.com/api/retail/prices?\$filter=armRegionName eq 'eastus' and armSkuName eq 'Standard_B1s' and priceType eq 'Consumption'" | jq '.Items[] | select(.productName=="Virtual Machines B Series") | {meterName, retailPrice}'
$ curl -s "https://prices.azure.com/api/retail/prices?..." | jq '...'
{ "meterName": "B1s", "retailPrice": 0.0104 }

$0.0104/hour vs. $0.096/hour for D2s_v5 — roughly a ninth of the cost, which is exactly why the free-tier lessons in this track default to Standard_B1s: it’s cheap enough that a forgotten VM for a day costs cents, not dollars.

4. Find which single resource cost the most this month.
az costmanagement query --type ActualCost --timeframe MonthToDate --scope "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33" --dataset-aggregation '{"totalCost":{"name":"PreTaxCost","function":"Sum"}}' --dataset-grouping name="ResourceId" type="Dimension" --query "sort_by(properties.rows, &[0])[-1]"
$ az costmanagement query ... --query "sort_by(properties.rows, &[0])[-1]"
[8.42, "/subscriptions/.../resourceGroups/learn-rg/providers/Microsoft.Compute/virtualMachines/learn-vm", "USD"]

Grouping by ResourceId instead of ResourceGroup or ServiceName goes down to individual resources — the level of detail needed once a resource group’s total looks high and the next question is “which resource inside it.”

5. State a cost-vs-reliability trade-off explicitly, the way a Well-Architected review would.
Decision: run Azure SQL Database on the Basic tier (5 DTU, no zone redundancy) instead of a
zone-redundant Premium tier.

Cost: Basic is billed at a small fraction of Premium's rate.
Reliability given up: no automatic failover across availability zones — a zone outage in
  the region causes downtime until Azure recovers the single instance, rather than an
  automatic failover to a healthy replica.
Acceptable because: this is a learning environment with no uptime requirement; the same
  choice on a production order-processing database would trade away reliability the
  business actually needs, and Premium's cost would be justified instead.

This is the format the Well-Architected Framework asks for: not “we chose the cheap option,” but which pillar was given up, by how much, and why that trade was acceptable for this specific workload.

This closes the Azure track. From here: terraform covers provisioning Azure resources (alongside AWS and GCP) as code with HCL instead of the CLI, and cloud-interviews covers scenario questions that span all three major clouds.

Frequently Asked Questions

What's the difference between Cost Management's cost analysis and a budget?
Cost analysis is a read-only, backward-looking breakdown of spend that already happened, sliced by resource group, service, tag, or time period. A budget is a forward-looking threshold you define in advance that can trigger an alert (or, for some scopes, an automated action) when actual or forecasted spend crosses it. Cost analysis answers 'what did we spend'; a budget answers 'tell me before we overspend'.
How much can a reserved instance actually save compared to pay-as-you-go?
It depends on the term and the SKU, and should be checked per-SKU rather than assumed — for a Standard_D2s_v5 Linux VM in East US, Azure's public Retail Prices API quotes pay-as-you-go at $0.096/hour ($840.96/year) against $519 total for a 1-year reservation (about 38% cheaper annualized) and $997 total for a 3-year reservation (about 61% cheaper annualized). Longer terms save more per hour but commit you to paying regardless of usage.
What are the five pillars of the Azure Well-Architected Framework?
Reliability, Security, Cost Optimization, Operational Excellence, and Performance Efficiency. They're explicitly framed as trade-offs against each other, not independent checklists — the framework's own guidance is that optimizing one pillar in isolation (say, cost) typically costs something in another (like reliability or performance), and a good design states which trade-off it's making and why.
Does a reservation cover any VM, or does it have to match the exact size and region I bought it for?
A reservation is scoped to a VM size flexibility group (e.g., the Dsv5 family), region, and OS, not one literal VM instance — it automatically applies its discount to any matching running VM in that scope, and Azure's instance size flexibility feature can even apply a partial discount across different sizes within the same family.