When a single node fails, every pod on that node fails with it. Spreading pods across availability zones eliminates that single point of failure. When workload components need to communicate, co-locating them in the same zone reduces cross-zone network latency and data transfer costs.
In ACK Pro clusters and ACK Serverless Pro clusters, Kubernetes-native scheduling—topologySpreadConstraints, nodeAffinity, and podAffinity—controls how Elastic Container Instance (ECI)-based pods are distributed across zones. This topic explains how to configure each approach with working examples.
Zone distribution and affinity take effect only when topologySpreadConstraints, nodeAffinity, or podAffinity is configured on a pod, or when the pod matches an existing resource policy.
Prerequisites
Before you begin, ensure that you have:
An ACK Pro cluster or ACK Serverless Pro cluster with:
Kubernetes version 1.22 or later
ACK Virtual Node component version 2.10.0 or later
kube-scheduler component version 5.9 or later, with the virtual node-based pod scheduling feature enabled. For details, see Enable the virtual node-based pod scheduling policy for an ACK cluster
Multiple zones (vSwitches) configured in the eci-profile so that pods can be scheduled across zones. For details, see Configure multiple zones to create a pod
Usage notes
Set
topologyKeytotopology.kubernetes.io/zone.The following configurations override zone distribution and affinity settings, making them take no effect:
The
k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered"annotation, which enforces a fixed vSwitch ordering strategy.The
k8s.aliyun.com/eci-fail-strategy: "fail-fast"annotation, which sets the pod fault-handling policy to fail-fast.
Choose a scheduling approach
| Goal | Approach | When to use |
|---|---|---|
| Spread pods evenly across all available zones | topologySpreadConstraints | High availability: a single zone outage affects only a fraction of replicas |
| Co-locate pods with existing pods in the same zone | podAffinity | Performance: new pods must run in the same zone as a related set of pods |
| Pin pods to a specific zone | nodeAffinity | Performance: a specific zone has network characteristics your workload requires |
Spread pods across zones using topology spread constraints
Topology spread constraints let you control the maximum imbalance between zones. The key parameter is maxSkew: it defines how far apart the pod counts across zones can be.
Set whenUnsatisfiable: DoNotSchedule to block scheduling when the constraint cannot be met, or ScheduleAnywaySpread constraint definition to allow scheduling even if the constraint is violated.
For the full parameter reference, see topologySpreadConstraints field.
The examples below use an ACK Serverless Pro cluster running Kubernetes 1.22.
Deploy a Deployment with zone spread
Create a file named
deployment.yamlwith the following content. This creates a 10-replica Deployment with a maximum skew of 1 across zones. The following optional parameters are also available intopologySpreadConstraints:topologySpreadConstraints: - maxSkew: <integer> minDomains: <integer> # Optional. Beta in Kubernetes 1.25 and later. topologyKey: <string> whenUnsatisfiable: <string> labelSelector: <object> matchLabelKeys: <list> # Optional. Beta in Kubernetes 1.27 and later. nodeAffinityPolicy: [Honor|Ignore] # Optional. Beta in Kubernetes 1.26 and later. nodeTaintsPolicy: [Honor|Ignore] # Optional. Beta in Kubernetes 1.26 and later.apiVersion: apps/v1 kind: Deployment metadata: name: with-pod-topology-spread labels: app: with-pod-topology-spread spec: replicas: 10 selector: matchLabels: app: with-pod-topology-spread template: metadata: labels: app: with-pod-topology-spread spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: with-pod-topology-spread containers: - name: with-pod-topology-spread image: registry.k8s.io/pause:2.0 resources: requests: cpu: "1" memory: "256Mi"Apply the manifest:
kubectl apply -f deployment.yamlVerify the scheduling result. Check which nodes the pods are running on:
kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"Check how many pods landed in each zone:
kubectl get po -lapp=with-pod-topology-spread -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c
How strict topology spread works
By default, the scheduler counts running pods when computing the spread—it does not wait for pending pods to be created. If ECI fails to create pods in some zones, the spread constraint based on maxSkew may be violated.
For example, suppose the scheduler places pods in Zone A, Zone B, and Zone C. If pod creation fails in Zone B and Zone C, Zone A ends up with more pods than allowed by maxSkew: 1, and no Elastic Container Instance-based pod runs in Zone B or Zone C. This violates the constraint specified by the maxSkew parameter.
ACK Serverless Pro clusters support strict topology spread to prevent this. With strict topology spread enabled, the scheduler first schedules a pod to each zone, and does not schedule pending pods until the scheduled pods are created:
The scheduler first places one pod in each zone. It holds subsequent pods until the initial set is created:
For instance, even after Pod A1 is created, pending pods are not scheduled. This is because if the pod in Zone B or Zone C fails to be created, the constraint specified by the maxSkew parameter is violated. After Pod B1 is created, kube-scheduler schedules a pod to Zone C. Pods with green shading are created.
To disable strict topology spread, set whenUnsatisfiable: ScheduleAnyway. For details, see Spread constraint definition.
Deploy pods to a specific zone using affinity
Use affinity when you need pods to land in a particular zone—either to co-locate with existing pods (podAffinity) or to target a specific zone by label (nodeAffinity).
Pin pods to a specific zone (nodeAffinity)
To target a specific zone, use nodeAffinity and specify the zone label value. The following example pins all pods to Beijing Zone A (cn-beijing-a).
Create a file named
deployment.yamlwith the following content:apiVersion: apps/v1 kind: Deployment metadata: name: with-affinity labels: app: with-affinity spec: replicas: 3 selector: matchLabels: app: with-affinity template: metadata: labels: app: with-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - cn-beijing-a containers: - name: with-affinity image: registry.k8s.io/pause:2.0Apply the manifest:
kubectl apply -f deployment.yamlVerify the scheduling result. Check which nodes the pods are running on:
kubectl get po -lapp=with-affinity -ocustom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | grep -v "<none>"Check the zone distribution:
kubectl get po -lapp=with-affinity -ocustom-columns=NODE:.spec.nodeName --no-headers | grep -v "<none>" | xargs -I {} kubectl get no {} -ojson | jq '.metadata.labels["topology.kubernetes.io/zone"]' | sort | uniq -c
What's next
Pod topology spread constraints — Kubernetes official referencePod Topology Spread Constraints
Assigning pods to nodes — covers node affinity and pod affinity in depth
Configure multiple zones to create a pod — set up the multi-zone vSwitch configuration required by this feature