Skip to main content

Add GPU nodes

Inspect 1.36

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.

What happens when a GPU server joins#

Once a supported GPU server joins the cluster, Syself Autopilot recognizes the card, makes the driver available, deploys the NVIDIA device plugin as a managed component, and labels the node autopilot.syself.com/gpu=true. The device plugin is the component that tells Kubernetes how many GPUs a node has, so pods can request them. A GPU pod then schedules with no manual setup: you do not install a driver, choose a special image, or turn anything on.

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 .

Verify the device plugin and capacity#

Confirm the node is recognized as a GPU node:

		$ kubectl get nodes -L autopilot.syself.com/gpu
	

Then confirm the GPU is schedulable. GPUs are exposed 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 .

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 .

Related: for scheduling with slices, or to fix a pod stuck Pending.