Syself Autopilot does not support durable node taints. A taint you set by hand does not survive, and there is no supported field to set one that sticks. Use labels and node affinity to control where pods run. ## Why a taint does not stick A taint on a `Node` repels pods: only a pod with a matching **toleration** (a pod-side field that says "I accept this taint") can schedule there. It is the inverse of a label, which attracts pods that opt in. Syself Autopilot builds on Cluster API (CAPI), which creates and replaces nodes from **templates**, declarative blueprints describing everything a new node should be. The limitation sits in Cluster API itself: its templates carry labels but have **no taint field**, so a taint can never be part of the blueprint a node is rebuilt from. A node is replaced on a cluster upgrade, a health-check recovery, or a manual removal (see [Self-healing and node replacement](/docs/hetzner/apalla/concepts/operations/self-healing-and-node-replacement) for what triggers each). Each new node starts clean, so a taint you add with `kubectl taint` is gone after the next replacement, and there is no supported way to make it persist. > [!NOTE] > The missing taint field is being worked on upstream. Cluster API has an experimental proposal to [propagate taints](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20250513-propogate-taints.md) from the pool template to the node, so a taint would survive replacement. Syself is following that work closely and will support durable taints once the feature is tested and proven stable. ## The control-plane taint is the one exception Control-plane nodes carry `node-role.kubernetes.io/control-plane:NoSchedule`. Syself Autopilot sets it at registration, and it is built into the control-plane template, so it persists across every replacement. It comes from the platform, not from a setting you apply, which is why ordinary workloads never land on control-plane nodes. It is the only taint on the cluster, and you do not manage it. ## Use labels and node affinity instead Labels set in the `Cluster` manifest propagate to the `Node` object and survive replacement. Combine a label with a `nodeSelector` or node affinity on your pods, and you place pods exactly where you want, durably. See [Label nodes and assign roles](/docs/hetzner/apalla/servers-and-nodes/pools/label-nodes-and-assign-roles) for the full rules, and [Node affinity and selectors](/docs/hetzner/apalla/servers-and-nodes/scheduling/node-affinity-and-selectors) for required-vs-preferred affinity. ## Keeping other pods off a pool Labels attract, they do not repel: a pod that sets no selector can still land on a labelled node. To reserve a pool, give it a role label, put a `nodeSelector` on the pods that belong there, and give every other workload its own pool to select, so nothing lands where it should not. For a boundary that does not depend on every pod being labelled correctly, a dedicated bare-metal pool is the hard separation; see [Dedicate node pools per client](/docs/hetzner/apalla/servers-and-nodes/fleet/dedicate-node-pools-per-client). ## Related - [Node affinity and selectors in practice](/docs/hetzner/apalla/servers-and-nodes/scheduling/node-affinity-and-selectors) - [Label nodes and assign roles](/docs/hetzner/apalla/servers-and-nodes/pools/label-nodes-and-assign-roles) - [Dedicate node pools per client](/docs/hetzner/apalla/servers-and-nodes/fleet/dedicate-node-pools-per-client)