Syself Autopilot runs NVIDIA GPU workloads on Hetzner bare-metal servers. The driver and everything a GPU pod needs are already on the node, so you never SSH in to install anything. ## GPU-capable server types GPUs are bare metal only. Order a Hetzner bare-metal server from the **GEX line**, or an auction server with a supported card. See Hetzner's [GPU server matrix](https://www.hetzner.com/dedicated-rootserver/matrix-gpu/) for the available models. **There is no Hetzner Cloud GPU type.** Syself Autopilot enables GPU support only for cards on its allowlist: - GeForce GTX 1080 and GTX 1080 Ti - RTX 4000 SFF Ada and RTX 6000 Ada - RTX PRO 6000 Blackwell (all three variants) Any other NVIDIA card, including older or unlisted models, is treated as a plain display adapter and gets no GPU support. ## Add a dedicated GPU pool Register the GPU servers as bare-metal hosts and attach them as their own pool, following [Add bare-metal servers](/docs/hetzner/apalla/servers-and-nodes/provision/add-bare-metal-servers). Give the pool a role label so you can steer workloads onto it: ```yaml - class: workeramd64baremetal name: md-gpu replicas: 2 metadata: labels: node-role.kubernetes.io/gpu: "" variables: overrides: - name: workerHostSelectorBareMetal value: matchLabels: hardware: gpu ``` Label the GPU hosts with `hardware: gpu` on their `HetznerBareMetalHost` objects, so `workerHostSelectorBareMetal` selects only them. See [Add bare-metal servers](/docs/hetzner/apalla/servers-and-nodes/provision/add-bare-metal-servers) for host labels. ## Verify the device plugin and capacity A node is a GPU node when Syself Autopilot labels it `autopilot.syself.com/gpu=true`, which it does only for cards on the [supported allowlist](#gpu-capable-server-types). The NVIDIA device plugin is a managed cluster component that deploys only on these labelled nodes; it is the component that tells Kubernetes a node has GPUs, advertising the `nvidia.com/gpu` resource that pods request. No label means no device plugin and no schedulable GPU. Confirm the node is recognized as a GPU node: ```console $ kubectl get nodes -L autopilot.syself.com/gpu ``` Then confirm the GPU is schedulable. The device plugin exposes each GPU as the `nvidia.com/gpu` resource, under both Capacity and Allocatable: ```console $ kubectl describe node | grep nvidia.com/gpu Capacity: nvidia.com/gpu: 4 Allocatable: nvidia.com/gpu: 4 ``` Each physical card exposes four slices through time-slicing, so `Capacity: 4` on a single-GPU server means one card, not four. A slice is an allocation token, not a quarter of the card, and pods that share a card share its memory with no quota between them. See [Share a GPU across pods](/docs/hetzner/apalla/workloads/specialized/share-a-gpu) for when co-scheduling is safe and how to keep a card to one workload. > [!NOTE] > `Allocatable: 0` means the device plugin is missing or unhealthy, not that the GPU is busy. See [GPU not scheduling](/docs/hetzner/apalla/servers-and-nodes/access/gpu-not-scheduling). > [!IMPORTANT] > A GPU node is not something you fix by hand; the sealed OS has no package manager. If a GPU node does not come up as GPU-capable and the logs do not explain it, reprovision the node. See [GPU not scheduling](/docs/hetzner/apalla/servers-and-nodes/access/gpu-not-scheduling). ## Request a GPU from a workload ```yaml apiVersion: v1 kind: Pod metadata: name: gpu-test spec: restartPolicy: Never nodeSelector: node-role.kubernetes.io/gpu: "" containers: - name: cuda-container image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0 resources: limits: nvidia.com/gpu: 1 ``` The `nodeSelector` is not required for scheduling. The `nvidia.com/gpu` request alone already steers the pod to a GPU node, because non-GPU nodes advertise no such resource. Set the `nodeSelector` anyway when you want the pod pinned to your dedicated pool, rather than to any GPU node in the cluster. A request for `nvidia.com/gpu: 2` or higher is rejected. The device plugin runs with `failRequestsGreaterThanOne`, so one GPU per container is the limit. ## Keep other pods off the GPU nodes The `nodeSelector` pulls GPU workloads onto the pool, but a label only attracts pods; it does not push others away. Syself Autopilot manages node labels through Cluster API and does not support node taints, so reserve GPU hardware structurally: keep the GPU servers in their own pool, and give every other workload its own pool to select with a `nodeSelector`, so nothing lands on the GPU nodes by accident. See [Label nodes and assign roles](/docs/hetzner/apalla/servers-and-nodes/pools/label-nodes-and-assign-roles). ## Related - [GPU not scheduling](/docs/hetzner/apalla/servers-and-nodes/access/gpu-not-scheduling) - [Run GPU workloads](/docs/hetzner/apalla/workloads/specialized/run-gpu-workloads) - [Share a GPU across pods](/docs/hetzner/apalla/workloads/specialized/share-a-gpu) - [Add bare-metal servers](/docs/hetzner/apalla/servers-and-nodes/provision/add-bare-metal-servers)