A pool is one `machineDeployments` entry in your `Cluster` resource: a class, a machine type, a count, and optional labels. Everything else you do to nodes (scaling, labels, mixing hardware, GPU nodes) builds on this one concept. ## A pool is one machineDeployments entry A pool is a single entry under `spec.topology.workers.machineDeployments` in your `Cluster` resource: ```yaml workers: machineDeployments: - class: workeramd64hcloud name: md-0 replicas: 3 failureDomain: nbg1 variables: overrides: - name: workerMachineTypeHcloud value: cpx42 ``` That entry declares a class, a machine type, a count, and (optionally) labels. `failureDomain` names the Hetzner region for this pool: | Code | Location | | ------ | -------------------- | | `fsn1` | Falkenstein, Germany | | `nbg1` | Nuremberg, Germany | | `hel1` | Helsinki, Finland | | `ash` | Ashburn, VA, USA | | `hil` | Hillsboro, OR, USA | | `sin` | Singapore | Syself Autopilot keeps that many nodes of that kind running. If the real count ever differs from what you declared, for example a machine dies, Syself Autopilot notices and brings it back to match. ## One class and one machine type per pool A pool has exactly **one class** and **one machine type**. To run different server types, or cloud alongside bare metal, or different roles, you create a pool for each. Each pool needs a unique `name`. That name appears in the machine names in Hetzner, so you can tell which pool a machine belongs to. You can run as many pools as you need, and [scale each one independently](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool). ## Cloud vs bare-metal classes The class picks the infrastructure. It is not a name you invent: you pick one of two platform-defined classes. | Class | Machines | | ---------------------- | -------------------------------------------------------------------------------- | | `workeramd64hcloud` | Hetzner Cloud VMs, created and destroyed on demand | | `workeramd64baremetal` | Hetzner dedicated servers, claimed from and released back to your host inventory | You can [mix both in one cluster](/docs/hetzner/apalla/servers-and-nodes/pools/mix-cloud-and-bare-metal). The control plane is configured separately under `spec.topology.controlPlane`, not as a worker pool. ## How a pool becomes Machines and Nodes When you apply the `Cluster` resource, Syself Autopilot runs a chain that turns the pool into running nodes: ```mermaid flowchart LR P["Pool: one machineDeployment"] --> M["Machine, one per replica"] M --> I[Cloud VM created, or bare-metal host claimed] I --> O[Syself Linux boots] O --> N[Node joins the cluster] ``` Each `Machine` (a Cluster API object that stands for one server) provisions its own infrastructure and boots [Syself Linux](/docs/hetzner/apalla/concepts/internals/syself-linux). It then joins the workload cluster as a `Node`. You declare the pool. Syself Autopilot runs the chain and keeps it in that shape. > [!NOTE] > Every pool boots the same Syself Linux image, on cloud and on bare metal. There is no per-pool or per-role image to pick. What runs on a node depends on its role (control plane or worker) and its hardware (for example a GPU), which Syself Autopilot detects and configures automatically, not on anything you set in the pool. A `machineDeployments` entry is not the only object involved. Cluster API expands it into a small tree. A different controller manages each level: ```mermaid flowchart TD MD["MachineDeployment
(One per worker pool)"] --> MS["MachineSet
(One active revision)"] MS --> M1["Machine"] MS --> M2["Machine"] MS --> M3["Machine"] M1 --> N1["Node (K8s worker)"] M2 --> N2["Node (K8s worker)"] M3 --> N3["Node (K8s worker)"] ``` | Object | Role | | ------------------- | ------------------------------------------------------------------- | | `MachineDeployment` | One per worker pool. Owns a `MachineSet`. | | `MachineSet` | Owns one `Machine` per replica. | | `Machine` | One machine equals one node. Triggers the provisioning chain above. | These are standard Cluster API objects, the same ones any Cluster API tooling understands. See [Cluster API resources](/docs/hetzner/apalla/reference/cluster-api-resources) to learn why that matters. To inspect them directly on the management cluster: ```console $ kubectl get machinedeployments,machinesets,machines -n ```
## Independent scaling Because each pool is its own machine deployment, changing one pool's `replicas` does not touch the others. Grow your backend pool without touching your GPU pool, or scale a burst pool to zero overnight. See [Scale a node pool](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool). The same independence holds during a cluster upgrade: after the control plane rolls, each worker pool rolls on its own schedule. A slow rollout in one pool does not delay the others. ## If you are coming from a UI-driven node pool A Syself pool is not a button in a console. It is a **declarative entry** in your `Cluster` manifest, versioned in Git if you use GitOps. There is no separate "pool object" to reconcile by hand: you edit the number, apply, and the platform converges. This is why every node task reads "edit the `Cluster` resource and re-apply" rather than a sequence of clicks. > [!TIP] > Syself Autopilot watches the `Cluster` object at all times and corrects drift on its own. If a machine dies or someone changes a setting directly on a server, you do not need to fix it by hand. See [Declarative cluster management](/docs/hetzner/apalla/concepts/foundations/declarative-cluster-management) for how that reconciliation loop works. ## Where to go next - [Add cloud servers](/docs/hetzner/apalla/servers-and-nodes/provision/add-cloud-servers) - [Scale a node pool](/docs/hetzner/apalla/servers-and-nodes/pools/scale-a-pool) - [Label nodes and assign roles](/docs/hetzner/apalla/servers-and-nodes/pools/label-nodes-and-assign-roles) - [Mix cloud and bare-metal pools](/docs/hetzner/apalla/servers-and-nodes/pools/mix-cloud-and-bare-metal) To see why running your own machines beats a managed control plane, see [managed Kubernetes](/docs/hetzner/apalla/concepts/overview).