Skip to main content

Label nodes and assign roles

Inspect 1.36

Put a label on a worker pool, and every node that pool creates carries it. Pods then use nodeSelector or (a rule that attracts pods to nodes with a specific label) to target that pool.

Prerequisites#

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:

cluster.yamlyaml
		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 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 .

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:

yaml
		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 .