AKS availability zones: the basics
What does a single-zone AKS cluster actually look like?
An Azure region is made up of independent physical locations called availability zones, each with its own power, cooling and networking. A zone can fail on its own without the rest of the region going with it. Azure Kubernetes Service can place the virtual machines that run your pods, the node pools, across several of those zones so that one datacentre failure takes out only a slice of your capacity rather than the whole cluster. The catch is that this is not the default for the nodes: unless you set availability zones when you create a node pool, AKS places its instances regionally, with no guarantee they are spread across zones, so a single zone outage can in the worst case take every node down at once.
It helps to separate the two halves of an AKS cluster. The control plane, the Kubernetes API server and its supporting services, is hosted and replicated across zones by Microsoft automatically, so you do not configure it and it stays up through a zone failure on its own. The node pools are different. They run as virtual machine scale sets in your own subscription, and their zone placement is entirely down to how you created them. A zone-resilient control plane in front of node pools that all sit in one zone still gives you an outage when that zone fails, because there is nowhere for your pods to run.
The other half of the picture is how traffic reaches the cluster. AKS provisions an Azure Standard load balancer by default, and a Standard load balancer is zone-redundant: its frontend keeps distributing inbound traffic even if one zone is down. The Basic load balancer, which was retired on 30 September 2025, did not offer this. So the reliable shape is the combination: node pools spread across zones, plus the zone-redundant Standard load balancer that AKS already gives you, so both the compute and the front door survive a single zone failure. This lesson is about getting every node pool into that shape.
In this lesson you will learn how AKS expresses zone placement, why the control plane being zone-resilient is not enough on its own, how to find every node pool that is not spread across zones, and how to move a cluster onto zone-resilient node pools and a zone-redundant Standard load balancer without dropping live traffic. The focus is the node pools you own, because that is the half of the cluster whose resilience is entirely your decision.
The control plane that stayed up while everything else fell over
AKS quietly does half the resiliency work for you and tells almost no one. The moment you create a cluster in a region with multiple availability zones, Microsoft spreads the managed control plane, the API server, the scheduler and etcd, across those zones automatically, at no cost and with nothing for you to configure. The trap is that this is so seamless people assume the whole cluster is zone-resilient. It is not. The nodes that actually run your pods sit wherever you placed them, and if you never set availability zones on the node pools, a single zone outage can leave you with a perfectly healthy control plane managing precisely zero running workloads. The half that is invisible works on its own; the half you can see is the half you have to configure.
Finding which node pools survive a zone failure
Priya runs the platform team at a payments company whose checkout API runs on AKS. After a competitor lost a region slice to a zone outage and went dark for an afternoon, she wants to know, before anyone asks, whether their own cluster would have survived the same event.
Rather than assume the cluster is fine because the control plane is managed, she lists the availability zones set on each node pool. An empty result for a pool means it was created without zones and is placed regionally, with no guarantee of being spread across datacentres.
List the availability zones configured on every node pool in the cluster. A pool with no zones is the one that goes down with a single datacentre.
An empty Zones value means the node pool was created without availability zones. The system pool here is the weak link: it hosts CoreDNS and metrics-server, so losing it degrades the whole cluster.
How AKS actually places nodes across zonesdeep dive
Zone placement lives on the agent pool profile, in the 'availabilityZones' property, a list such as ['1','2','3']. When it is set, AKS deploys that node pool's underlying virtual machine scale set across the named zones and balances nodes between them on a best-effort basis. When it is empty or null, the pool runs in regional mode: instances are placed somewhere in the region with no guarantee they are spread across zones, or even that they land in different ones. So the difference between a resilient pool and a fragile one is whether this single property was set at creation time.
The constraint that shapes the whole migration is that you cannot change the number of availability zones on a node pool after it is created. There is no in-place edit. To make an existing single-zone pool resilient you create a new pool with the zones set, cordon and drain the workloads off the old one, and delete it. This is why the work is a planned migration rather than a settings change, and why it needs a maintenance window rather than a single command.
Two further details matter in practice. First, the node SKU has to support the zones you ask for: AKS rejects pool creation if the chosen virtual machine size is not offered in those zones in that region, which you can check with 'az aks list-vm-skus' before you migrate. Second, if you run the cluster autoscaler, Microsoft recommends one node pool per zone rather than a single zone-spanning pool, because the autoscaler treats a pool as one unit and cannot request a node in a specific zone, so a multi-zone pool can leave pods pending during a scale-up. For a fixed-size pool, a single zone-spanning pool is the simpler shape.
What is the impact of leaving node pools in a single zone?
The direct impact is a correlated outage. A node pool placed in one zone is a single point of failure: when that datacentre loses power, cooling or networking, every node in the pool goes down together, and so does every pod scheduled on it. Because the failure is correlated, you do not lose a node here and a node there that the scheduler can route around, you lose the whole pool at once. If that pool is the system pool, CoreDNS and metrics-server go with it and the rest of the cluster degrades even where nodes survive. The control plane staying up, which it does, does not help, because there is nowhere for the workloads to run.
The second-order impact is the gap between perceived and actual resilience. Teams routinely believe an AKS cluster is zone-resilient because the control plane is, and discover only during an incident that the nodes never were. That is the worst moment to find out: the assumption that the platform would ride out a zone failure goes untested until a zone actually fails, and by then the migration that would have prevented it cannot be done in a hurry, because you cannot change the zones on a running pool in place.
The reliability framing is straightforward. Spreading node pools across zones turns a full outage on a zone failure into a partial, recoverable degradation: you lose the capacity in the failed zone, the load balancer keeps serving from the others, and the cluster autoscaler or your spare headroom brings replacement capacity up in the healthy zones. The same event that takes a single-zone cluster fully offline becomes a few minutes of reduced capacity for a zone-spanning one. That is the entire value of the capability, and Microsoft documents it as carrying no additional Azure charge.
How do you move node pools across zones safely?
Treat this as a planned migration, not a config tweak, because you cannot change the zones on an existing pool in place. The order matters: stand up the zone-spanning pool first, move workloads onto it, and only then retire the old single-zone pool, so the service never loses all its capacity at once.
1. Inventory every node pool by zone placement
List the availability zones set on each node pool across your clusters. Any pool with an empty or null zone list is in regional mode and can land entirely in one zone. Treat this inventory as the source of truth and tag each pool with the workload it runs, so the migration can be ordered by how much a zone outage would actually cost.
2. Confirm the SKU and load balancer support what you need
Check that the node virtual machine size is offered in all the zones you intend to use in that region with 'az aks list-vm-skus', because pool creation fails otherwise. Confirm the cluster uses the zone-redundant Standard load balancer, which is the AKS default and the only supported SKU since the Basic load balancer was retired on 30 September 2025, so the front door survives a zone failure too.
3. Create the zone-spanning pool, then drain and delete the old one
Add a new node pool with availability zones set across the region's zones. Cordon and drain the workloads off the single-zone pool so Kubernetes reschedules them onto the zone-spanning one, confirm everything is healthy, then delete the old pool. Doing it in this order means the service always has somewhere to run and you never drop all of its capacity at once.
4. Prove it, and make zones the default for new pools
Verify the new placement by reading back the zones and the node topology labels, then test resilience by cordoning and draining a zone's worth of nodes and watching traffic carry on from the others. Bake availability zones into the Bicep or templates your team uses to create node pools, so future pools are zone-spanning by default rather than by memory.
# 1. Confirm the node SKU is offered in the zones you want, in this region.
az aks list-vm-skus \
--location eastus \
--size Standard_D4ds_v5 \
--all \
--output table
# 2. Add a new zone-spanning user node pool across all three zones.
# --zones is a space-separated list; the pool must be a VirtualMachineScaleSets pool.
az aks nodepool add \
--resource-group prod-rg \
--cluster-name checkout-aks \
--name apppoolz \
--node-count 6 \
--zones 1 2 3
# 3. Drain the old single-zone pool so Kubernetes reschedules onto the new one,
# then remove it once everything is healthy.
for node in $(kubectl get nodes -l agentpool=apppool -o name); do
kubectl drain "$node" --ignore-daemonsets --delete-emptydir-data
done
az aks nodepool delete \
--resource-group prod-rg \
--cluster-name checkout-aks \
--name apppool
# 4. Verify the new pool really is spread across zones.
kubectl get nodes -o custom-columns='NAME:metadata.name, ZONE:metadata.labels.topology\.kubernetes\.io/zone' Quick quiz
Question 1 of 5An AKS cluster's control plane is managed and replicated across zones by Microsoft. Does that mean the cluster survives a single zone failure?
You scored
0 / 5
Keep learning
Go deeper on how AKS expresses zone placement, how to configure it, and how to test that your cluster really survives a zone failure.
- Configure availability zones in Azure Kubernetes Service (AKS) The exact CLI and Terraform steps to create zone-spanning and zone-aligned node pools, plus how to validate node placement.
- Zone resiliency recommendations for Azure Kubernetes Service (AKS) Microsoft's recommendations for zone-redundant clusters, pod spread, the Standard load balancer, and one node pool per zone with the autoscaler.
- Reliability in Azure Kubernetes Service (AKS) How the control plane and node pools differ in zone behaviour, and how to test for availability zone resiliency.
You can now treat AKS zone resilience as one capability rather than a setting you hope someone remembered: inventory which node pools have availability zones set, confirm the SKU and the zone-redundant Standard load balancer support what you need, stand up zone-spanning pools and drain onto them before retiring the single-zone ones, then prove it with a tested failover and make zones the default for new pools. The control plane was always resilient; now the half you own is too.
Back to the library