Add cloud servers
To add cloud capacity, add one worker pool to your Cluster resource, pick a machine type and a region, and apply. A worker pool is one machineDeployments entry. Syself Autopilot then requests the machines, installs Syself Linux , and joins them to the workload cluster.
Prerequisites#
- Access to the management cluster Syself runs for you (or your GitOps repository that syncs to it).
- An existing
Clusterobject. If you have not created one yet, start with creating your first cluster .
Add a machine deployment#
Add an entry to spec.topology.workers.machineDeployments. Each entry is one pool, with a single machine type and a unique name that shows up in the machine names in Hetzner.
apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
name: mycluster
spec:
clusterNetwork:
services:
cidrBlocks: ["10.128.0.0/12"]
pods:
cidrBlocks: ["192.168.0.0/16"]
serviceDomain: "cluster.local"
topology:
classRef:
name: hetzner-apalla-1-36-v2
version: v1.36.3
controlPlane:
replicas: 3
workers:
machineDeployments:
- class: workeramd64hcloud
name: md-0
replicas: 5
failureDomain: nbg1
variables:
overrides:
- name: workerMachineTypeHcloud
value: cpx42
- class: workeramd64hcloud
name: md-1
replicas: 3
failureDomain: nbg1
variables:
overrides:
- name: workerMachineTypeHcloud
value: cx53
class: workeramd64hcloud is the fixed class for x86 cloud workers. Every cloud pool uses it and the same underlying node image, so only name, replicas, failureDomain, and the workerMachineTypeHcloud override change between pools.
Because a pool carries a single machine type, you create a separate machine deployment for every type you want to run. The example above runs five cpx42 machines and three cx53 machines. You can define as many pools as you like and scale them independently .
Pick the machine type#
We support all Hetzner Cloud types with at least 4 GB of RAM, shared or dedicated vCPU:
- CPX (Regular): the balanced default. For control planes, use at least a CPX32 (4 vCPU / 8 GB); CPX42 gives most clusters better headroom.
- CCX (Dedicated): dedicated vCPU for latency-sensitive or CPU-bound workloads.
- CX (Cost-optimized): cheapest, but older hardware with limited availability and variable performance.
Warning
Exercise caution with the CX line. Its performance is not guaranteed (older shared hardware with variable CPU speed), and its limited availability means replacements may not be purchasable in your location when a pool scales or heals. Reserve it for autoscaling or variable workloads that tolerate both.
Tip
If you skip the workerMachineTypeHcloud override, the pool defaults to cpx32 (4 vCPU / 8 GB). The control plane's controlPlaneMachineTypeHcloud variable defaults to cpx32 too, so set it explicitly once your cluster grows past a handful of nodes.
Note
ARM (CAX) machine types are not supported. Due to significant declines in the availability and reliability of Hetzner's ARM servers, we can no longer recommend them. This is a temporary measure, and we will restore support once the situation improves. Use an x86 type (CPX, CCX, or CX).
For the machine types you can pick from, see Server types and sizing .
Set the region#
The region variable sets where your infrastructure lives. All control-plane nodes stay in one region. A machine deployment's failureDomain picks a specific location (a zone) inside that region.
spec:
topology:
variables:
- name: region
value: nbg1
Hetzner has regions in the EU (Germany and Finland), the US, and Singapore.
Worker nodes can run in different locations. The single-region rule is only about the control plane, so you can place worker pools wherever your workload needs them. Cross-region traffic pays for the distance, though: pods on workers in different regions talk with noticeably higher latency than same-region pods, so keep chatty workloads together.
Note
Because you choose the region, you control data residency. Keeping a cluster in an EU region keeps its data in the EU, which matters for sovereignty and compliance.
Neither reason is helped by spreading the control plane:
- Access goes through one load balancer. Your
kubectlconnection reaches the API server through a control-plane load balancer, and a load balancer lives in a single location. If that location has an outage, access from outside the cluster fails wherever the other control-plane nodes sit. Spreading them does not save the case you care about. - etcd would pay latency on every write. etcd, the control-plane database, is consensus-based, not eventually consistent: a write returns only once a majority of members agree on it. Members in different locations add network latency to every write, all the time, for a benefit only during a rare failure.
A control-plane outage does not stop your workloads. They keep running. You just cannot change Kubernetes objects until the control plane is back, and most clusters do not change the API every few minutes. Trading a rare, short, often-harmless window for lower day-to-day latency is the better default.
For real resilience across locations, do not stretch one cluster. Run separate clusters in different locations or regions and fail over between them, or run active-active at the workload level.
A region can still put two machines on the same physical host. To spread a pool's machines across separate hosts, so one hardware failure cannot take out more than one at a time, see Spread nodes with placement groups .
Apply and watch the machines come up#
Apply the change #
Apply the edited Cluster resource to the management cluster (or let your GitOps controller sync it).
Watch the machines #
$ kubectl get machines -w
New Machine objects appear, each provisions a Hetzner Cloud server, and the node joins the workload cluster a few minutes later.
A new node needs a few seconds after it boots before it can run pods. In that gap, the platform finishes connecting the node to Hetzner, its IP addresses and its provider ID, and only then lets the scheduler place pods on it. This normally takes seconds, not minutes.
Under the hood: Kubernetes marks a new node with a node.cloudprovider.kubernetes.io/uninitialized taint, a flag that keeps pods off, and the Hetzner cloud-controller-manager removes it once the node is wired up.
Scale by changing replicas#
To grow or shrink the pool, change replicas and re-apply. See Scale a node pool for what happens on scale-up and scale-down, or Autoscale a cluster to let the autoscaler do it.
When to add a second pool instead#
Add another machine deployment rather than resizing an existing one when you need a different machine type, a different role or label, or a different failure domain. One pool is one class and one type, so any of those differences is a new pool. To give a pool an identity your workloads can target, add a metadata.labels block to its machine deployment. Label nodes and assign roles walks through it. For control-plane sizing and count, see High-availability control plane .
Caution
You can also change workerMachineTypeHcloud on an existing pool instead of adding a new one. Syself then replaces every node in that pool with the new type: it drains each node (waiting for PodDisruptionBudgets, the objects that limit how many pods of a workload can be down at once, to allow it), then removes the node regardless and brings up a replacement.
A new pool avoids that churn. The old nodes keep running while the new type comes up alongside them.