Skip to main content

Add GPU nodes

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 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 . 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 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. 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:

		$ 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:

		$ kubectl describe node <gpu-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 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 .

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 .

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 .