Using Azure Kubernetes Service Cluster Autoscaler with Node Pool Labels for Workload‑Specific Scaling
Learn how to label AKS node pools and configure the cluster autoscaler so frontend and batch workloads scale independently, reducing cost and avoiding over‑provisioning.
05 May 2026, 07:43 UTC

When a single AKS cluster runs both latency‑sensitive web services and nightly batch jobs, the default autoscaler often adds nodes indiscriminately. This can leave expensive nodes idle for batch workloads while the web tier waits for capacity, or cause unnecessary scaling that drives up cost. By labeling node pools and configuring the cluster autoscaler to respect those labels, you can direct pods to the appropriate pool and let the autoscaler grow or shrink each pool only when its labeled workload demands it.
Labeling node pools
Node pool labels are ordinary Kubernetes labels that the autoscaler reads when deciding which pool to expand. You add them with the Azure CLI; the label key can be anything that reflects your workload class, for example workload.
# Replace and with your values
az aks nodepool update \
--resource-group \
--cluster-name \
--name frontendpool \
--node-labels workload=frontend
az aks nodepool update \
--resource-group \
--cluster-name \
--name batchpool \
--node-labels workload=batch
After the update, each node in the pool carries the label. You can verify with kubectl get nodes --show-labels and look for the workload column.
Autoscaler configuration
Enable the cluster autoscaler on the AKS cluster and set a minimum and maximum node count for each labeled pool. The --balance-similar-node-groups flag tells the autoscaler to avoid creating many nearly‑identical pools, which reduces fragmentation.
az aks update \
--resource-group \
--cluster-name \
--enable-cluster-autoscaler \
--min-count 1 \
--max-count 5
# Set per‑pool limits (repeat for each pool)
az aks nodepool update \
--resource-group \
--cluster-name \
--name frontendpool \
--cluster-autoscaler-profile scan-interval=10s,new-pod-scale-up-delay=0s,max-graceful-termination-sec=30 \
--min-count 1 \
--max-count 3
az aks nodepool update \
--resource-group \
--cluster-name \
--name batchpool \
--cluster-autoscaler-profile scan-interval=10s,new-pod-scale-up-delay=0s,max-graceful-termination-sec=30 \
--min-count 0 \
--max-count 4
The autoscaler will now only add nodes to a pool when pods that match that pool’s labels cannot be scheduled on existing nodes.
Worked example: web API and nightly batch
Imagine a web API Deployment that requires low latency and a batch Job that runs once per night.
- Web API:
replicas: 5, pod template includesnodeSelector: {workload: "frontend"}. - Batch Job: pod template includes
nodeSelector: {workload: "batch"}and runs with aschedule: "0 2 * * *"CronJob.
During peak traffic, the autoscaler sees unschedulable frontend pods and scales the frontendpool up to three nodes. The batch pool stays at zero nodes because no batch pods are pending. When the CronJob triggers at 02:00, the batch pool scales out to accommodate the Job, then scales back to zero after completion.
You can observe this behavior in autoscaler events:
kubectl get events --field-selector reason=ScalingActive --sort-by=.metadata.creationTimestamp
Look for messages that mention the node pool name and the label that triggered the scale‑up.
Trade‑off and limitation
Label‑based autoscaling adds operational overhead:
- Every pod must specify a
nodeSelector,affinity, ortolerationthat matches a pool label; otherwise the pod may remain unschedulable. - Too many distinct label values lead to many node pools, increasing management complexity and potentially hitting subscription limits on node cores.
- The autoscaler version must be recent enough to honor custom labels; older releases ignore them and scale based on total cluster demand only.
To mitigate, start with a small pilot namespace, enforce label usage through Azure Policy or admission controllers, and monitor autoscaler events before expanding to production workloads.
Actionable closing
- Label your existing node pools with a workload identifier (
az aks nodepool update --node-labels workload=...). - Enable the cluster autoscaler and set min/max counts per pool (
az aks update --enable-cluster-autoscalerfollowed by per‑pool--min-countand--max-count). - Deploy representative pods with matching
nodeSelectoror affinity rules. - Validate scheduling with
kubectl get pods -o wideand check autoscaler events viakubectl get eventsor Azure Monitor for AKS. - Iterate: adjust labels, pool sizes, and affinity rules based on observed scaling patterns.
By aligning node pool labels with workload characteristics, you let the AKS cluster autoscaler add resources where they are truly needed, reducing waste and improving responsiveness for latency‑sensitive services.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.