Label nodes and assign roles
Put a label on a worker pool, and every node that pool creates carries it. Pods then use nodeSelector or node affinity (a rule that attracts pods to nodes with a specific label) to target that pool.
Prerequisites#
- Access to the management cluster. See Access the management cluster .
- A
Clusterobject already applied.
Add labels to a worker pool#
Each worker pool is one entry under spec.topology.workers.machineDeployments.
Add a metadata.labels block #
Add it to the pool, at the same level as name, replicas, and failureDomain:
apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
name: mycluster
namespace: my-org
spec:
topology:
classRef:
name: hetzner-apalla-1-36-v2
version: v1.36.3
controlPlane:
replicas: 3
workers:
machineDeployments:
- class: workeramd64hcloud
name: md-0
replicas: 3
failureDomain: fsn1
metadata:
labels:
node-role.kubernetes.io/backend: ""
node.cluster.x-k8s.io/environment: production
variables:
overrides:
- name: workerMachineTypeHcloud
value: cpx42
Note
Only add a metadata: block when you actually have labels to set. In v1beta2, do not add an empty metadata: {} placeholder.
Apply the Cluster resource #
Apply it directly, or let GitOps sync it:
$ kubectl apply -f cluster.yaml
Syself reads metadata.labels from each pool and writes them onto the matching node objects in the workload cluster, on top of the labels it sets on every node automatically. See Node labels and annotations for those system labels.
Confirm the label landed #
$ kubectl get nodes -l node-role.kubernetes.io/backend
This lists every node that carries the label, so you can check the pool reached the nodes you expect.
Which labels reach the node#
Only labels in these domains reach the node:
| Domain | Example |
|---|---|
node-role.kubernetes.io | node-role.kubernetes.io/backend: "" |
node-restriction.kubernetes.io | node-restriction.kubernetes.io/location: fsn1 |
node.cluster.x-k8s.io | node.cluster.x-k8s.io/environment: production |
A label in any other domain, for example mycompany.com/tier: critical, does not reach the node. Syself does not report an error; the label is silently dropped.
Warning
Role labels under node-role.kubernetes.io/ use an empty-string value (""), not "true". A nodeSelector or affinity rule on a pod must match the exact key and value. A pod selecting node-role.kubernetes.io/backend: "true" does not match a node labelled node-role.kubernetes.io/backend: "".
System labels Syself already sets#
You do not have to label a node to describe what it is. Syself Autopilot already tags every node with a handful of labels you can select on directly:
| Label | Value | On |
|---|---|---|
autopilot.syself.com/machine-type | hcloud or baremetal | every node |
node.kubernetes.io/instance-type | the server type, for example cpx42 | every node |
node-role.kubernetes.io/control-plane | empty | control-plane nodes |
node.kubernetes.io/worker | true | worker nodes |
instance.hetzner.cloud/is-root-server | true | bare-metal nodes |
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 | nodes with a working GPU |
So before you invent a label, check whether one of these already says what you mean. The full list, and what sets each one, is in Node labels and annotations .
Multiple pools with different roles#
Each machineDeployments entry is a separate pool with its own labels. Add several entries to give different groups of nodes different roles. Machine type and labels are independent settings, so a staging pool can use a smaller machine type while carrying its own label. This manifest declares a production pool and a staging pool side by side:
workers:
machineDeployments:
- class: workeramd64hcloud
name: md-production
replicas: 3
failureDomain: fsn1
metadata:
labels:
node-role.kubernetes.io/backend: ""
node.cluster.x-k8s.io/environment: production
variables:
overrides:
- name: workerMachineTypeHcloud
value: cpx42
- class: workeramd64hcloud
name: md-staging
replicas: 2
failureDomain: fsn1
metadata:
labels:
node-role.kubernetes.io/backend: ""
node.cluster.x-k8s.io/environment: staging
variables:
overrides:
- name: workerMachineTypeHcloud
value: cpx32
Each pool needs a unique name.
Tip
You can mix cloud and bare-metal pools in the same cluster: class: workeramd64hcloud for cloud, class: workeramd64baremetal for bare metal. Each pool gets its own metadata.labels. See Mix cloud and bare-metal pools .
Related#
- Node affinity and selectors in practice : match pods to the labels you just set.
- Node taints are not supported : why to use labels, not taints.