Skip to content

· 3 min read

AKS cost optimization: where the money actually goes

A practical checklist for cutting Azure Kubernetes Service spend: node pools, requests and limits, autoscaling, spot capacity, non production schedules and the monitoring bill nobody watches.

  • AKS
  • Azure
  • Kubernetes
  • Cost

Most AKS bills are not high because Kubernetes is expensive. They are high because the cluster was sized for a launch, then nobody went back. The good news is that the biggest savings usually come from a handful of boring changes, and none of them need a new tool.

This is the order I work through when a team asks why their AKS bill keeps growing.

1. Find out what you are paying for

Before changing anything, split the bill. In Azure Cost Management, group by resource group and meter category. For an AKS setup you will typically see four buckets:

  • Virtual machines: the node pools. Usually the largest line.
  • Managed disks: OS disks and persistent volumes, including ones whose pods are long gone.
  • Networking: load balancers, public IPs, NAT gateway and egress.
  • Log Analytics or your monitoring vendor: often the surprise.

If the node resource group (MC_...) is not tagged, tag the cluster resources so you can allocate costs to teams or environments later.

2. Fix requests before you touch nodes

The scheduler packs pods by their requests, not by what they really use. If every service requests 1 CPU and 2Gi "to be safe", the cluster autoscaler adds nodes that sit mostly idle.

Compare requests with actual usage over a normal week:

sum by (namespace, pod) (rate(container_cpu_usage_seconds_total{container!=""}[5m]))
/
sum by (namespace, pod) (kube_pod_container_resource_requests{resource="cpu"})

Anything consistently under 30% is a candidate for a smaller request. Do memory more carefully than CPU: memory limits that are too tight end in OOMKills, which are far more expensive than a slightly larger node.

3. Right size the node pools

Once requests are honest, look at the pools:

  • Fewer, larger nodes waste less on system overhead per node, but each node failure moves more pods. Pick a middle ground for your workload.
  • Separate pools for workloads with different shapes, for example memory heavy workers, so they do not force every node to be large.
  • Keep the system pool small and use taints so application pods do not land on it.

4. Let it scale

Turn on the cluster autoscaler for user pools and set sensible minimums. Add HPA for stateless services, or KEDA if scaling should follow a queue length rather than CPU.

The goal is simple: at 3am on a Sunday the cluster should be smaller than at 11am on a Tuesday. If it is not, you are paying for peak all week.

5. Use spot capacity where interruptions are fine

Spot node pools can cut compute cost dramatically for batch jobs, CI runners, preview environments and stateless workers that tolerate restarts. Keep anything stateful or latency critical on regular nodes, and use taints and tolerations so only the right workloads land on spot.

6. Switch off what nobody uses

Dev and staging clusters rarely need to run nights and weekends. AKS supports stopping a cluster, or you can scale user pools to zero on a schedule. Preview environments should delete themselves when the pull request merges.

7. Watch the monitoring bill

Observability spend grows quietly with every new label and log line. On one platform I worked on, the Grafana Cloud bill was cut by roughly 71% without losing visibility, by finding the root causes of metric growth and fixing them at the source. The usual levers are:

  • Dropping high cardinality labels (request IDs, user IDs) from metrics
  • Not ingesting debug logs from production by default
  • Shorter retention for noisy, low value streams

The full story is in the AI platform case study.

The same applies to Container Insights and Log Analytics: check which tables ingest the most and whether anyone queries them.

8. Commit to what is left

Only after the cluster is lean, buy reservations or a savings plan for the steady baseline. Committing first locks in waste for one to three years.

A short checklist

  • Bill split by service, environment and meter
  • Requests compared with real usage and lowered where safe
  • Node pools sized for the workload, system pool tainted
  • Cluster autoscaler and HPA or KEDA enabled
  • Spot pools for interruption tolerant work
  • Non production environments scheduled off
  • Monitoring ingestion and retention reviewed
  • Reservations bought for the baseline only

If you want a second pair of eyes on your cluster, a cloud cost review usually finds the biggest leaks in the first few days.

Want a hand with this?

Tell me about your setup and I will suggest the smallest change that makes a real difference.