Topology-Aware Node Labels
Spreading NetBox pods and stateful workloads across availability zones, rather than only across nodes, requires each node to carry topology labels such as topology.kubernetes.io/zone. Embedded Cluster has no runtime mechanism to pass per-node labels during the join process, so you apply these labels with kubectl after each node joins the cluster.
Why topology labels matter
The Kubernetes scheduler and storage drivers read well-known topology labels to make placement decisions. Without these labels on your nodes, the cluster treats every node as belonging to the same failure domain, and a single zone outage can take down all replicas of a workload.
Topology labels enable three things:
- Pod topology spread constraints: The scheduler can distribute NetBox replicas evenly across zones using
topologySpreadConstraints, so no single zone holds every replica. - Storage replication across zones: CSI drivers that honor topology can place volume replicas in separate zones, keeping data available when a zone fails.
- Scheduler affinity: Node affinity and anti-affinity rules can target or avoid specific zones.
Use the well-known label keys that Kubernetes schedulers and CSI drivers expect:
topology.kubernetes.io/zonefor the availability zonetopology.kubernetes.io/regionfor the broader region
Values are arbitrary strings that you define (for example, us-east-1a). They must be consistent across nodes and match the values referenced in your scheduling constraints.
Label nodes after they join
Apply labels with kubectl after each node joins. This works for any number of zones, requires no release changes, and lets you assign each node to whatever zone it physically runs in.
These commands run inside the Embedded Cluster shell, which provides a preconfigured kubectl. See Accessing your cluster for details.
-
Enter the cluster shell:
/var/lib/embedded-cluster/bin/netbox-enterprise shell -
List the nodes to find their names:
kubectl get nodes -
Apply a zone label to each node, using the zone where that node actually runs:
kubectl label node <node-name> topology.kubernetes.io/zone=us-east-1aAdd a region label as well if your scheduling or storage rules use it:
kubectl label node <node-name> topology.kubernetes.io/region=us-east-1 -
Verify the labels are present:
kubectl get nodes -L topology.kubernetes.io/zone -L topology.kubernetes.io/region
The label persists on the node object for the life of that node. If you remove a node and rejoin it later, the label is gone and you must reapply it. Build this step into your node provisioning runbook so rejoined or replacement nodes are labeled consistently.
Validation
After labeling your nodes, confirm the labels propagated and that scheduling behaves as expected.
Confirm every node reports the expected zone:
kubectl get nodes -L topology.kubernetes.io/zone
To test scheduling behavior, apply a topologySpreadConstraints block to a workload. The following constraint asks the scheduler to keep the replica count within one across zones:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: netbox
Confirm the pods landed in different zones by checking which node each pod runs on, then cross-referencing the node labels:
kubectl get pods -o wide
Known limitations
Embedded Cluster does not provide a first-class way to pass per-node labels during the join process. Labels applied with kubectl are not preserved across a node removal and rejoin. Runtime per-node label support is not currently available. Track your zone assignments and reapply labels as part of node provisioning.