Skip to main content

Node affinity and selectors in practice

Inspect 1.36

Once your pools carry , you can steer pods onto them. Use nodeSelector for the simple case, and node affinity when you need conditions. The pod's selector must match the label's exact key and value.

nodeSelector for the simple case

nodeSelector pins a pod to nodes that carry every label listed:

yaml
		spec:
  nodeSelector:
    node-role.kubernetes.io/backend: ""
	
yaml
		spec:
  nodeSelector:
    autopilot.syself.com/machine-type: baremetal
	

Match the exact key and empty-string value

Role labels under node-role.kubernetes.io/ use an empty-string value (""), not "true". A selector for "true" does not match a node labelled "":

yaml
		# Node label set by the pool:   node-role.kubernetes.io/backend: ""
nodeSelector:
  node-role.kubernetes.io/backend: "true"
  node-role.kubernetes.io/backend: ""
	
Note

Only labels in the node-role.kubernetes.io, node-restriction.kubernetes.io, and node.cluster.x-k8s.io domains reach the node from a pool definition. Any other label is silently dropped, so a selector for it never matches. See for the full rule.

Combine pool labels with system labels

Syself also sets labels on every node before your pool's labels land. You can select on these without declaring them anywhere:

Label Value Where
autopilot.syself.com/machine-type baremetal or hcloud every node
instance.hetzner.cloud/is-root-server "true" bare-metal nodes
node.kubernetes.io/instance-type for example cpx42 every node
topology.kubernetes.io/region location on cloud, network zone on bare metal every node
topology.kubernetes.io/zone datacenter on cloud, location on bare metal every node
autopilot.syself.com/gpu "true" GPU nodes
kubernetes.io/hostname the node's hostname every node

nodeSelector requires every listed label to match. Combine one of your pool's labels with a system label to narrow further. This pod schedules only on a node that is in the backend pool and bare metal:

yaml
		spec:
  nodeSelector:
    node-role.kubernetes.io/backend: ""
    autopilot.syself.com/machine-type: baremetal
	

See for the full list.

Need rules, not just labels

nodeSelector matches labels and stops there. When you need a hard-or-soft choice, matching operators like In or Exists, or placement relative to other pods, see . To spread replicas evenly as your node count changes, see .

Affinity rules read the same node labels a nodeSelector does, so the exact-key rule and the system-label table above apply to them too.

Why unmatched pods go elsewhere

A selector or affinity rule attracts. It does not repel. A pod that sets no selector can still land on your labelled nodes. A pod whose preferred affinity cannot be met just schedules somewhere else.