# Aks Cost Analysis

> Break down Azure Kubernetes Service spend by cluster, namespace, and utilization bucket. Identifies the most expensive clusters and namespaces, and how much spend sits in idle vs active workloads. WHEN: "AKS cost", "Kubernetes cost", "cluster cost", "namespace cost", "container cost", "break down AKS", "AKS utilization", "idle pods", "chargeback AKS". INVOKES: query_aks_costs, generate_query, validate_query, execute_query

- Skill: `azure-samples/aks-cost-analysis` (Agent Skill)
- Install (CLI): `npx skillmds@latest add azure-samples/aks-cost-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/azure-samples/aks-cost-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: MIT
- Author: Azure-Samples (https://skillmd.com/u/azure-samples)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/azure-samples/aks-cost-analysis

---


# AKS Cost Analysis

Break down AKS spend by cluster, namespace, and utilization bucket. Surfaces the highest-spend clusters and namespaces, and how much spend sits in idle vs active workloads.

> **Prerequisite:** The AKS Cost Analysis add-on must be enabled on the cluster(s). When the add-on isn't enabled, `query_aks_costs` returns no cost data. See Step 1 for the enablement check, and [Enable AKS Cost Analysis](https://learn.microsoft.com/en-us/azure/aks/cost-analysis) for setup instructions.

> **Run the ARG query through the generate → validate → execute workflow.** The Step 1 query is ready to run, but pass it to `validate_query` first — it confirms the syntax and property paths before you spend a call on `execute_query`. If you need to adapt it to a different resource type or field, draft it with `generate_query` (a natural-language prompt), then validate and execute.

## Step 1: Verify Clusters Exist and Cost Analysis is Enabled

First, confirm AKS clusters exist on the scope. Call `execute_query` with this Azure Resource Graph query (replace the `<sub-id-…>` placeholders with the target subscription IDs):

```kusto
Resources
| where type =~ 'Microsoft.ContainerService/managedClusters'
| where subscriptionId in ('<sub-id-1>', '<sub-id-2>')
| extend costAnalysisEnabled = tobool(properties.metricsProfile.costAnalysis.enabled)
| project name, resourceGroup, location, subscriptionId, costAnalysisEnabled
| order by subscriptionId, name
```

If the response includes a `skipToken`, re-call `execute_query` with that token to fetch the next page and merge results — large tenants may return clusters across multiple pages.

Clusters with `costAnalysisEnabled = false` won't produce cost rows in Steps 2–3 — flag those clusters in your output so missing rows aren't mistaken for zero spend.

Then call `query_aks_costs` with groupBy=Cluster as a probe. If it returns no cost rows but clusters exist, the add-on isn't enabled — point users to the enablement steps linked above and re-run after enablement.

If no clusters exist, surface that and stop.

## Step 2: Cluster-Level Breakdown

Call `query_aks_costs` with timeframe=MonthToDate, groupBy=Cluster. If the result is empty (common early in the billing cycle, before the current month has cost data), retry with timeframe=TheLastMonth and label the window in your output so the user knows which period the numbers cover. Report:

- Cost per cluster, sorted descending.
- The top 1–3 clusters by cost — these are where investigation pays off in the next steps.

Use the same timeframe choice (MTD or TheLastMonth) for Step 3.

## Step 3: Namespace Breakdown for Top Clusters

For each of the top 1–3 clusters from Step 2, call `query_aks_costs` with groupBy=Cluster,Namespace, `filterDimension=Cluster` + `filterValues=<cluster resource ID>` (see note below), and the same timeframe you settled on in Step 2. Surface:

- Top 5 namespaces by cost per cluster.
- Separate platform / system namespaces (`kube-system`, `gatekeeper-system`, etc.) from application namespaces — platform overhead vs team workloads tells you different things.

> **Filter values:** for the `Cluster` dimension, pass the full ARM resource ID exactly as it appears in Step 2's response (typically lowercased: `/subscriptions/<id>/resourcegroups/<rg>/providers/microsoft.containerservice/managedclusters/<name>`).

> **Cost categories in the Namespace dimension.** Rows like `#service charges#` (service-level charges such as Uptime SLA and Defender for Containers), `#idle charges#` (provisioned capacity not used by any workload), `#system charges#` (node capacity AKS reserves for system processes like the kubelet and container runtime), and `#unallocated charges#` (cost that couldn't be attributed to a namespace) are cluster-level cost categories, not real namespaces — present them separately and don't recommend workload deletes against them.

## Step 4: Idle and Overhead Split

Using the Step 3 result (no new query needed), split each top cluster's spend into three buckets:

- **Idle** (`#idle charges#`) — provisioned capacity no workload consumed. This is the primary optimization signal.
- **Overhead** (`#service charges#` + `#system charges#` + `#unallocated charges#`) — service, system-reservation, and unattributed cost.
- **Allocated** — the sum of the real namespace rows (everything that isn't a `#…#` category).

A cluster where Idle is a large share of total spend is a strong candidate for node-pool resizing, cluster-autoscaler tuning, or workload consolidation.

> For pod-level CPU/memory metrics behind the spend, use Azure Monitor / Container Insights separately.

## Step 5: Recommendation & Handoff

Based on what Steps 2–4 surfaced, route the user to the right next step:

- **Idle / low-utilization dominates a cluster** → hand off to **cost-optimization**: review node-pool SKUs, enable cluster autoscaler, and tune HPA / VPA (or KEDA for event-driven workloads) on the top namespaces.
- **One namespace dominates a cluster's cost** → suggest a chargeback conversation with the owning team. Look for ownership / cost-center tags on the cluster resource via ARG (common names: `Owner`, `CostCenter`, `BusinessUnit`) — exact keys vary by org. If the cluster is multi-tenant, confirm namespace ownership before attributing.
- **Compute pattern is stable and well-utilized** → hand off to **commitment-analysis** for a **Reservation** scoped to the node-pool SKU family, or a **Compute Savings Plan** covering the cluster's broader compute spend (SP is flexible across SKUs, regions, and OS). Note: Spot node pools don't receive RI/SP discounts, so subtract Spot spend before sizing the commitment.

## Presentation

- **AKS portfolio** — Total AKS spend for the reporting window, cluster count, subscription count.
- **Top clusters** — Cluster, RG, region, spend for the reporting window.
- **Top namespaces per cluster** — Per top cluster, top 5 namespaces by spend, with system vs app namespaces called out.
- **Idle & overhead** — Per top cluster, $ in Idle / Service / System / Unallocated vs allocated workload spend; flag clusters with a large Idle share.
- **Next step** — One concrete recommendation: which cluster to investigate first and which skill to use next.

