Upgrading AKS Clusters Safely
Kubernetes version upgrades are a routine operational task on AKS, but done carelessly they can cause workload downtime. This page covers how to check available versions, execute upgrades safely, use PodDisruptionBudgets to protect applications, and understand what actually happens to your nodes during an upgrade.
Kubernetes version lifecycle on AKS
AKS supports the three most recent minor versions of Kubernetes. When a new minor version is released, the oldest supported version enters a deprecation window and is removed from support approximately 12 months after its release date. AKS adds a new patch version automatically when one is available, but minor version upgrades are always manual.
Check which versions are currently available in your region:
# List all available Kubernetes versions in your region
az aks get-versions \
--location eastus \
--output table
# Check available upgrades for your specific cluster
az aks get-upgrades \
--resource-group myResourceGroup \
--name myAKSCluster \
--output tableThe output of az aks get-upgrades shows your current version, available upgrade targets, and whether each target is a patch or minor upgrade. It will not list versions you cannot upgrade to from your current version — skipping minor versions is not offered.
To check the current version of your cluster and node pools:
az aks show \
--resource-group myResourceGroup \
--name myAKSCluster \
--query "{controlPlane:kubernetesVersion, nodePools:agentPoolProfiles[].{name:name, version:orchestratorVersion}}" \
--output tableThe upgrade process: control plane first, then node pools
AKS upgrades happen in two phases. The control plane (API server, scheduler, etcd) is upgraded first. During this phase, the Kubernetes API remains available with at most a brief disruption. Node pools are upgraded second — the control plane must always be at a version equal to or one minor version ahead of the node pools.
# Upgrade both control plane and all node pools in one command
az aks upgrade \
--resource-group myResourceGroup \
--name myAKSCluster \
--kubernetes-version 1.29.5
# Upgrade only the control plane (node pools stay on current version)
az aks upgrade \
--resource-group myResourceGroup \
--name myAKSCluster \
--kubernetes-version 1.29.5 \
--control-plane-only
# After upgrading the control plane, upgrade a specific node pool
az aks nodepool upgrade \
--resource-group myResourceGroup \
--cluster-name myAKSCluster \
--name nodepool1 \
--kubernetes-version 1.29.5Upgrading the control plane separately first is useful if you want to test workload compatibility with the new version before upgrading nodes. A node pool on version N-1 is fully compatible with a control plane on version N.
The az aks upgrade command is synchronous by default and can take 15–60 minutes depending on cluster size. Add —no-wait to return control immediately, then monitor with az aks show or watch node status in the portal.
What happens to nodes during an upgrade
For each node in a node pool, AKS performs four steps in sequence:
- Provision a new node — a new VM is created at the target Kubernetes version and added to the node pool. This is the surge node.
- Cordon the old node — the old node is marked as unschedulable. No new pods are placed on it, but existing pods continue running.
- Drain the old node — Kubernetes evicts all pods from the old node. They are rescheduled onto other available nodes including the new surge node. This is where PodDisruptionBudgets come into play.
- Delete the old node — once drained, the old VM is removed from the node pool.
This process repeats for each node. With the default surge of 1, only one node is being upgraded at a time. With a higher surge, multiple nodes can be upgraded in parallel.
Set the max surge for a node pool to speed up large upgrades:
# Set max surge to 2 nodes (absolute number)
az aks nodepool update \
--resource-group myResourceGroup \
--cluster-name myAKSCluster \
--name nodepool1 \
--max-surge 2
# Set max surge to 33% of node pool size
az aks nodepool update \
--resource-group myResourceGroup \
--cluster-name myAKSCluster \
--name nodepool1 \
--max-surge 33%The drain step evicts pods by sending them a SIGTERM signal. Applications that handle SIGTERM gracefully — flushing connections, finishing in-flight requests, then exiting — will have zero dropped requests during the drain. Applications that do not handle SIGTERM will be force-killed after the terminationGracePeriodSeconds (default 30 seconds).
Using PodDisruptionBudgets to prevent downtime
A PodDisruptionBudget (PDB) limits how many pods from a Deployment can be simultaneously unavailable during voluntary disruptions — which includes node drains during upgrades. Without a PDB, Kubernetes might evict all replicas of your application simultaneously if they happen to be on the same nodes being drained.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-server-pdb
namespace: production
spec:
minAvailable: 2
selector:
matchLabels:
app: api-serverThis PDB says: when evicting pods with the label app: api-server, always keep at least 2 pods available. If the Deployment has 3 replicas and the upgrade wants to drain a node that has 2 of those replicas, the drain will pause until those pods are rescheduled elsewhere and become ready before continuing.
Alternatively, specify the maximum number that can be unavailable:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-server-pdb
namespace: production
spec:
maxUnavailable: 1
selector:
matchLabels:
app: api-serverApply the PDB before starting an upgrade:
kubectl apply -f pdb.yaml
# Verify the PDB
kubectl get pdb -n production
kubectl describe pdb api-server-pdb -n productionA PDB with minAvailable set to the total number of replicas will prevent the drain from completing. For example, a PDB of minAvailable: 3 on a Deployment with only 3 replicas means no pod can ever be evicted. The upgrade will stall indefinitely. Always leave room for at least one pod to be evicted.
Testing in staging first
The most effective risk mitigation for upgrades is running a staging cluster that matches production and upgrading it first. A staging upgrade catches API deprecations, admission webhook incompatibilities, and add-on failures before they hit production.
Key things to check after upgrading staging:
- All pods start and pass readiness probes on the new version.
- Add-ons (Container Insights, Key Vault CSI driver, ingress controller) still function.
- Any custom admission webhooks (ValidatingWebhookConfiguration, MutatingWebhookConfiguration) are compatible with the new API version.
- Deprecated API versions in your YAML manifests. For example, certain Ingress and PodSecurityPolicy API versions were removed in Kubernetes 1.25. Run
kubectl api-versionsto see what is available.
# Check for use of deprecated APIs in your cluster (requires Pluto or kubectl deprecations)
kubectl get ingress --all-namespaces -o yaml | grep "apiVersion"
# Show all API resources available in the new version
kubectl api-resources --api-group=networking.k8s.ioAuto-upgrade channels
AKS supports auto-upgrade channels that automatically upgrade your cluster when new versions are available. These reduce manual work but require confidence that your workloads handle upgrades without intervention.
| Channel | What gets upgraded | Best for |
|---|---|---|
| none | Nothing automatically | Full manual control |
| patch | Patch versions only (1.28.3 to 1.28.5) | Most production clusters |
| stable | Patch + minor versions on the N-1 stable minor | Dev/staging clusters |
| rapid | Patch + minor versions on the latest minor | Keeping up with latest features |
| node-image | Node OS image only, not Kubernetes version | Security patches without version bump |
# Set the auto-upgrade channel
az aks update \
--resource-group myResourceGroup \
--name myAKSCluster \
--auto-upgrade-channel patchCombine auto-upgrade with planned maintenance windows so upgrades only occur during off-peak hours. Configure maintenance windows in the portal or with az aks maintenanceconfiguration add.
Common mistakes
- Upgrading production without testing in staging first. Each minor Kubernetes version removes deprecated API versions and may change default behavior for admission controllers, RBAC, and networking. Deploying directly to production without a staging run means discovering incompatibilities under real traffic. Maintain a staging cluster and always upgrade it at least a week before production.
- No PodDisruptionBudgets on critical workloads. Without PDBs, the node drain during an upgrade may simultaneously evict all replicas of a Deployment if they are co-located on the same node — for example, all three replicas on a three-node cluster where each node runs one replica. The pods restart quickly, but there is a period of complete unavailability. A PDB with
maxUnavailable: 1prevents this. - Ignoring version skew between control plane and node pools. After upgrading the control plane with
—control-plane-only, node pools must be upgraded before the version gap exceeds one minor version. A node pool on version 1.27 with a control plane on 1.29 is outside the supported skew policy and may exhibit unexpected behavior. Complete node pool upgrades promptly after the control plane upgrade.
Summary
- Use
az aks get-upgradesto see available target versions; you cannot skip minor versions and must upgrade sequentially through each one. - Upgrades work by provisioning surge nodes, cordoning and draining old nodes, then deleting them — repeating until all nodes are on the new version.
- PodDisruptionBudgets with
minAvailableormaxUnavailableprevent node drains from taking down all replicas of a workload simultaneously. - Always test upgrades in staging first, and use the
patchauto-upgrade channel for most production clusters to keep patch versions current automatically.
Frequently asked questions
How often do I need to upgrade my AKS cluster?
Kubernetes releases three minor versions per year (e.g., 1.28, 1.29, 1.30). AKS supports each minor version for approximately 12 months. Once a version is within 60 days of end-of-support, AKS sends deprecation warnings. You should plan to upgrade at least once per year to stay on a supported version. Microsoft does not force upgrades but does end support, which means no security patches for unsupported versions.
Can I skip minor versions when upgrading?
No. You cannot skip minor versions. If your cluster is on 1.27 and the latest is 1.30, you must upgrade to 1.28 first, then 1.29, then 1.30. Patch version upgrades within the same minor version (1.28.5 to 1.28.9) can be done in a single step. Plan time for sequential minor version upgrades.
What is node surge and why does it matter?
Node surge is the number of extra nodes AKS provisions during an upgrade. With a surge of 1, AKS adds one new node, drains one old node onto it, then removes the old node — repeating until all nodes are upgraded. Higher surge means faster upgrades but higher temporary cost. The default surge is 1. Setting it to 33% of the node pool size upgrades roughly one-third of nodes in parallel, which is much faster for large pools.