← All posts
azurefinopsakscost-optimization

AKS cost analysis: what those namespace numbers actually mean before you bill a team for them

AKS Cost Analysis will happily show you a per-namespace cost breakdown — but Idle, System and Unallocated charges can make that number mean something very different from what a platform team expects. Here is how to read it correctly.

Every platform team running a shared AKS cluster eventually gets the same request from finance: “can you tell us what each team’s namespace actually costs us?” The instinctive answer is to enable the AKS cost analysis add-on, point at the Kubernetes namespaces view, and forward the number. That’s the fast way to get a number. It is not always the fast way to get a correct one — and handing a team a chargeback figure that’s 40% Idle and System charges they have no control over is how FinOps initiatives lose credibility with engineering.

Here’s what’s actually behind those namespace numbers, and how to use them without starting an argument you can’t win.

What you’re turning on

Cost analysis for AKS is an add-on built on top of the open-source OpenCost project. It reconciles Kubernetes-level usage data with your actual Azure invoice, then surfaces it in Cost Management under three views at the subscription scope:

  • Kubernetes clusters — aggregated cost per cluster.
  • Kubernetes namespaces — cost per namespace across all clusters in the subscription.
  • Kubernetes assets — cost of the underlying Compute, Networking and Storage resources.

Enabling it is a one-flag change, at cluster creation or on an existing cluster:

az aks update --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --enable-cost-analysis

Before you flip that flag, check the fine print, because each of these has bitten someone:

  • Your cluster needs the Standard or Premium tier — not Free — and once cost analysis is enabled you can’t downgrade back to Free without disabling it first.
  • Kubernetes cost views only exist for Enterprise Agreement and Microsoft Customer Agreement subscriptions. Pay-as-you-go and other offer types don’t get this data at all.
  • The cluster needs a managed identity and the Azure Disk CSI driver enabled — not a given on older clusters that predate both becoming defaults.
  • The add-on isn’t available in a handful of sovereign/national cloud regions.
  • It scales to roughly 7,000 containers per cluster, based on a 4 GB memory limit for the agent (roughly 200 MB + 0.5 MB per container) — large multi-tenant clusters can hit this ceiling.
  • Enabling it deploys a cost-analysis-identity managed identity with read access to the node resource group. If your node pool commands already rely on the node’s default managed identity via IMDS, you now need to specify which identity explicitly, since there’s more than one on the node.
  • Data isn’t real-time: budget 8 to 24 hours before a namespace’s numbers reflect reality.

None of that is a reason not to enable it — it’s genuinely the only Azure-native way to get Kubernetes-construct-level cost data reconciled against your real invoice. It’s just not a five-minute checkbox you flip and immediately trust.

The four charge types that decide whether the number is fair

This is the part that actually matters when you’re about to put a dollar figure next to a team’s name. The Kubernetes namespaces view doesn’t just split your bill proportionally by resource requests — it breaks every namespace’s cost into charge types, and only one of them is fully “owned” by the namespace:

Charge typeWhat it represents
Idle chargesCapacity you’re paying for that no workload is actually using.
System chargesCapacity AKS reserves on every node for the kubelet, container runtime and other system processes — reserved automatically, before your workloads ever get scheduled.
Service chargesAdd-on features like Uptime SLA or Microsoft Defender for Containers.
Unallocated chargesCosts that couldn’t be attributed to any namespace at all.

Namespace A running a lean, well-bin-packed workload on a mostly-full node looks cheap. Namespace B — the only workload on an otherwise near-empty node — inherits a disproportionate share of that node’s Idle and System charges, even though its own pods might request nearly nothing. If you forward the raw per-namespace total as a chargeback number without breaking out these four categories first, you’re effectively billing Namespace B’s team for your cluster’s bin-packing efficiency, not for what they consumed.

The fix isn’t complicated, but it has to be deliberate:

  • Show Idle and System charges as a separate cluster-level line, owned by the platform team, not redistributed into namespace totals under a chargeback model.
  • If you must allocate them, allocate proportionally to requested resources across namespaces on the same node — and say so explicitly in whatever report reaches finance.
  • Track Unallocated charges as its own signal: a persistently high Unallocated number usually means workloads outside the standard node pools, or gaps in how the add-on is attributing certain resource types — worth a look before you present the totals as final.

Where to actually look at it

Cost analysis surfaces through the standard Cost Management Cost analysis view at subscription scope — either from the subscription’s own blade, or from Cost Management directly by picking a Kubernetes view (clusters, namespaces, or assets) under Customizable views. The clusters view lets you drill straight into a specific cluster’s namespaces or assets from there.

One toggle worth knowing about if you’re running reservations or savings plans against the node pools: by default these views show actual costs, and you can switch to amortized costs (spreading a reservation’s upfront cost across its term) from the Customize menu. If your organization already amortizes everywhere else in Cost Management, turn this on here too — otherwise a cluster covered by a large upfront reservation purchase will show a cost spike in the month of purchase and near-zero afterward, which makes month-over-month namespace trending useless.

Putting it into a chargeback model that survives contact with engineering

The practical pattern that holds up:

  1. Enable the add-on per cluster (it’s per-cluster, not subscription-wide — if you run several clusters in one subscription, each one needs --enable-cost-analysis individually).
  2. Let data settle for at least 24 hours before pulling a report anyone will act on.
  3. Export the namespace view with charge types broken out, not collapsed into one number.
  4. Present Idle and System charges as a shared platform cost, split by an agreed formula (headcount, requested vCPU share, or a flat per-namespace tax) — not silently folded into each team’s number.
  5. Revisit Unallocated charges monthly; a growing Unallocated bucket is usually a sign the cluster’s shape has changed (new node pools, workloads outside standard namespaces) faster than your reporting has.

Cost Analysis for AKS gives you real, invoice-reconciled numbers down to the namespace — which is more than most Kubernetes cost tools manage without a separate billing integration. The value is genuine. Just don’t let the first chargeback report be the one where a team discovers their “cost” was mostly someone else’s idle capacity.


Sources & further reading: Azure Kubernetes Service (AKS) cost analysis, View Kubernetes costs - Microsoft Cost Management, Understand AKS usage and costs, AKS node resource reservations.