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](/docs/hetzner/apalla/concepts/internals/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 `Cluster` object. If you have not created one yet, start with [creating your first cluster](/docs/hetzner/apalla/getting-started/create-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.
```yaml vars persistBlur title="cluster.yaml"
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-v4
version: v1.36.4
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](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool).
## 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](/docs/hetzner/apalla/reference/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.
```yaml title="cluster.yaml"
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 `kubectl` connection 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](/docs/hetzner/apalla/servers-and-nodes/provision/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
```console
$ 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. The `node.cloudprovider.kubernetes.io/uninitialized` taint tracks this.
## Scale by changing replicas
To grow or shrink the pool, change `replicas` and re-apply. See [Scale a node pool](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool) for what happens on scale-up and scale-down, or [Autoscale a cluster](/docs/hetzner/apalla/clusters/configure/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](/docs/hetzner/apalla/servers-and-nodes/pools/label-nodes-and-assign-roles) walks through it. For control-plane sizing and count, see [High-availability control plane](/docs/hetzner/apalla/clusters/configure/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, then removes the node even if PodDisruptionBudgets are blocking the drain, and brings up a replacement.
>
> A new pool avoids that churn. The old nodes keep running while the new type comes up alongside them.
## Related
- [Scale a node pool](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool)
- [Spread nodes with placement groups](/docs/hetzner/apalla/servers-and-nodes/provision/placement-groups)
- [Server types and sizing](/docs/hetzner/apalla/reference/server-types-and-sizing)
- [Using Cluster Autoscaler](/docs/hetzner/apalla/clusters/configure/autoscale-a-cluster)