CUDA, cuDNN und das NVIDIA Container Toolkit: ein vernünftiger Einrichtungsweg für einen KI-Server

Sie haben einen frisch eingebauten Server mit vier oder acht GPUs, Ubuntu 22.04 oder 24.04, den NVIDIA-Treiber gepinnt (gemäß L01), und nvidia-smi liefert plausible Werte. Das ist das Fundament. Darüber liegt ein sperriger Stack — CUDA, cuDNN, das Container-Toolkit, die Runtimes, die NGC-Images —, um den sich die meisten Anleitungen herumdrücken. Dieser Artikel führt vom Treiber bis zu dem Punkt, an dem docker run --gpus all jede Karte anspricht und ein vLLM-Container Tokens ausliefert.

Mit klarer Haltung dazu, welcher Weg der richtige ist — und ehrlich dazu, welcher zubeißt.

Das Dreigespann aus Treiber, Runtime und Toolkit

Unter dem Oberbegriff „CUDA“ werden drei Dinge ausgeliefert, die ständig miteinander verwechselt werden:

Komponente Wo es liegt Was es tut Wer es installiert
NVIDIA-Treiber Kernelmodul + Userspace Spricht mit der GPU. Besitzt das Gerät. Setzt PCIe-Status, Leistungsaufnahme und Taktraten. Betriebssystem / apt / DKMS
CUDA-Runtime Userspace .so Bibliotheken Implementiert die CUDA-API, gegen die Ihre Anwendung linkt. App-Bundle oder System
CUDA-Toolkit nvcc, Header, Beispiele Kompiliert CUDA-C++ zu PTX/SASS. Notwendig zum Bauen, nicht zum Ausführen. apt oder NGC-Image

Zur Laufzeit zählt der Treiber. Ein Treiber unterstützt eine maximale CUDA-Runtime-Version; die Runtime muss dieser entsprechen oder älter sein. Das Toolkit brauchen Sie nur, wenn Sie CUDA-Code selbst kompilieren — bei 95% der Installationen benötigen Sie kein nvcc auf dem Host.

Genau deshalb funktionieren Container: Das Image bringt seine eigene CUDA-Runtime mit, der Host braucht nur den Treiber. Der Treiber auf dem Host ist das Einzige, was stimmen muss. Alles andere ist portabel.

┌─────────────────────────────────────────────────┐
│ Container: PyTorch 2.9 + CUDA 13.0 Runtime      │  ← im Image enthalten
│ Container: vLLM + CUDA 13.0 Runtime             │  ← im Image enthalten
├─────────────────────────────────────────────────┤
│ Host: NVIDIA-Treiber 570.x                      │  ← das Einzige, was der Host braucht
│ Host: nvidia-container-toolkit                  │  ← verbindet Treiber → Container
└─────────────────────────────────────────────────┘

Dieses Bild ist der Unterschied zwischen einem Nachmittag Arbeit und drei Tagen Abhängigkeitshölle.

CUDA 12.x oder 13.x — welche Version wählen

Im Mai 2026 sind beide aktiv im Einsatz. Die ehrliche Matrix für die Workloads, die auf Kentino-Servern laufen:

Stack CUDA 12.4–12.8 CUDA 13.0+
PyTorch stabil 2.5 / 2.6 (12.4–12.6) 2.9 / 2.10 / 2.11 (13.0+)
vLLM Stable-Wheels 12.8-Wheels werden weiterhin ausgeliefert 13.0 ist das Standard-Wheel auf PyPI ab v0.20
llama.cpp Funktioniert mit beiden Funktioniert mit beiden
TensorRT-LLM An das NGC-PyTorch-Image gebunden (25.12 → 13.0) Nativ
Blackwell (5090, RTX Pro 6000, B70) Erfordert mindestens 12.8+ Am besten unterstützt
Ada (4090, L40, L4) Vollständig unterstützt Vollständig unterstützt

Die Kentino-Standardwahl bei neuen Builds ist CUDA 13.0. Jede GPU der Produktlinie (5090, 4090, RTX Pro 6000 Blackwell, L40, L4) wird unterstützt, vLLM liefert auf PyPI inzwischen standardmäßig 13.0-Wheels aus, das Image vllm/vllm-openai verwendet 13.0, PyTorch 2.11 (wogegen vLLM gebaut wird) ist für 13.0 kompiliert, und neue Funktionen (FlashAttention 3 auf Blackwell, FP8-Trainings-Kernel) zielen zuerst auf 13.x.

Bleiben Sie nur dann bei 12.8, wenn Sie: einen fixierten Benchmark reproduzieren, ein Hersteller-SDK noch nicht nachgezogen hat oder ausschließlich Karten vor Blackwell einsetzen. Nichts älter als 12.4 bei Neuinstallationen — die entsprechenden Fehler wurden vor zwei Jahren upstream behoben.

Treiber und CUDA sauber installieren

Ubuntu 24.04 LTS (22.04 ist identisch). Der saubere Weg führt über das CUDA-Repository von NVIDIA für apt als Quelle:

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update

# Treiber + CUDA-Runtime-Bibliotheken. Kein nvcc — nur was Apps zum Laufen brauchen.
sudo apt install -y cuda-drivers-570 cuda-runtime-13-0

# Optional das komplette Toolkit (nvcc, Header). Nur wenn Sie auf dem Host kompilieren.
# sudo apt install -y cuda-toolkit-13-0

sudo reboot

Nach dem Neustart sollte nvidia-smi den Treiber 570.x und CUDA 13.0 melden. Fallen, die Sie vermeiden sollten:

  • Installieren Sie nicht das cuda Metapaket, sofern Sie nicht wirklich alles wollen. Es zieht Toolkit, Samples, GDS und Nsight nach sich und pinnt Pakete, die Sie nie haben wollten. Wählen Sie cuda-runtime-13-0 oder cuda-toolkit-13-0 explizit aus.
  • Pinnen Sie den Treiber, damit unattended-upgrades das Kernelmodul nicht austauschen kann: sudo apt-mark hold cuda-drivers cuda-drivers-570 nvidia-driver-570 nvidia-dkms-570 libnvidia-compute-570.
  • Immer nur ein Treiber-Branch. Das Mischen von 550- und 570-Paketen erzeugt ein System, das zwar bootet, bei dem aber nvidia-smi einen kryptischen Versionskonflikt meldet. Die Lösung lautet apt purge '*nvidia*' '*cuda*' und von vorn beginnen — besser, es gar nicht so weit kommen zu lassen.

cuDNN — apt oder Tarball?

cuDNN ist die Bibliothek der Deep-Learning-Primitive — Convolution, Attention, RNN. PyTorch, TensorFlow und JAX bauen darauf auf. Seit 9.x gibt es zwei Installationswege.

apt (empfohlen):

sudo apt install -y libcudnn9-cuda-13 libcudnn9-dev-cuda-13

Installiert nach /usr/lib/x86_64-linux-gnu/, wird vom dynamischen Linker gefunden und ist in die Paketverwaltung eingebunden, sodass Sicherheitsupdates automatisch durchlaufen. Es kann immer nur eine CUDA-Variante von cuDNN 9 gleichzeitig installiert sein — nicht libcudnn9-cuda-12 und libcudnn9-cuda-13 parallel über apt.

Tarball:

# Aus dem Redist-Manifest unter developer.download.nvidia.com/compute/cudnn/redist/ holen
tar -xf cudnn-linux-x86_64-9.5.0.x_cuda13-archive.tar.xz
sudo cp -r cudnn-linux-x86_64-*/include/* /usr/local/cuda/include/
sudo cp -r cudnn-linux-x86_64-*/lib/* /usr/local/cuda/lib64/

Ein Tarball ergibt Sinn, wenn mehrere cuDNN-Versionen auf einem Host liegen sollen, bei Air-Gap-Bundles oder wenn Sie auf Micro-Versionen pinnen. In allen anderen Fällen: apt. NVIDIAs Dokumentation empfiehlt, wo immer möglich, die Distributionspakete — der Tarball ist kein Installer, sondern ein Redistributions-Archiv.

Ehrliche Antwort: Wenn Sie NGC-Container einsetzen, installieren Sie cuDNN gar nicht erst auf dem Host. Es ist im Image enthalten.

Container oder Bare-Metal — wann was

Die größte Einzelentscheidung im Stack, und es gibt keine allgemeingültige Antwort. Die Abwägung, wie sie sich an realen Kentino-Builds zeigt:

Dimension Bare-Metal Container
Spitzendurchsatz 100% (Basiswert) 99–100% (vernachlässigbar)
Einrichtungszeit Stunden, danach wochenlange Drift Minuten, das Image ist die Spezifikation
Reproduzierbarkeit Schlecht — der Host-Zustand zählt Hervorragend — das Image ist eingefroren
Mandantenfähigkeit Umständlich Nativ
Mehrere CUDA-Versionen Mühsam, immer nur eine Trivial, ein Image pro Version
Performance-Debugging Einfacher (weniger Schichten) Schwieriger (cgroups, Namespaces)
Auswirkung eines Treiber-Upgrades Alles muss neu getestet werden Nur der Host muss neu getestet werden

Der Performance-Unterschied zwischen containerisiertem und Bare-Metal-CUDA ist auf modernen Kerneln vernachlässigbar — schlimmstenfalls ein einstelliger Prozentwert, meist reines Rauschen. Wer etwas anderes behauptet, misst Storage oder Netzwerk, nicht GPU-Rechenleistung.

Bare-Metal: wenn Sie für eine Publikation den letzten 2–3% nachjagen, beim Kernel-Debugging mit cuda-gdb / compute-sanitizer / Nsight, wo die Container-Schicht im Weg steht, oder wenn ein einziger Prozess die Maschine über Jahre für sich hat.

Container (die Kentino-Standardwahl): Mehrbenutzer-Maschinen, PyTorch 2.5 und 2.11 nebeneinander, der Wechsel zwischen Inferenz-Frameworks (vLLM, SGLang, TensorRT-LLM) ohne Neuaufbau des Hosts, oder ein Deployment, das Sie per docker pull auf einen neuen Server holen und in fünf Minuten laufen haben.

Für ein Robotiklabor oder eine Forschungsgruppe: Container. Für ein Benchmark-Rig mit einem einzigen Workload ist Bare-Metal völlig in Ordnung.

nvidia-container-toolkit — was es ist und wie Sie es einrichten

Das Toolkit ist der Kleber, der einem Container Zugriff auf die GPU des Hosts verschafft. Ohne es schlägt nvidia-smi im Container fehl. Mit ihm sieht der Container den Treiber, die Geräte und einen eingeschleusten Runtime-Stub.

Installation:

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
  | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# Smoke-Test
docker run --rm --gpus all nvidia/cuda:13.0.0-base-ubuntu24.04 nvidia-smi

Der letzte Befehl sollte die nvidia-smi Ausgabe des Hosts aus dem Container heraus anzeigen. Wenn das klappt, ist der Stack sauber verdrahtet.

Podman

Podman nutzt CDI:

sudo nvidia-ctk runtime configure --runtime=podman
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml

podman run --rm --device=nvidia.com/gpu=all \
  nvcr.io/nvidia/pytorch:25.12-py3 nvidia-smi

Rootless Podman + CDI ist die sauberste Lösung für Mehrbenutzer-Maschinen, auf denen Sie Nutzer nicht in die Gruppe docker aufnehmen wollen (was faktisch Root-Rechten entspricht).

CDI oder Legacy-Runtime

Zwei Modi, um GPUs bereitzustellen:

  • Legacy nvidia Runtime-Hook — das, was --gpus all seit Jahren verwendet. Docker ruft einen Hook auf, der Treiberbibliotheken und Geräte zur Laufzeit in den Container einhängt.
  • CDI (Container Device Interface) — eine offene Spezifikation zur Deklaration von Gerätezugriffen. nvidia-ctk cdi generate schreibt eine YAML-Datei, die GPUs als benannte Geräte auflistet (nvidia.com/gpu=0, nvidia.com/gpu=all); jede CDI-fähige Runtime kann sie nutzen.

Stand Mitte 2026:

Modus Docker Podman Kubernetes (GPU Operator) Rootless
Legacy Standard, funktioniert Funktioniert Veraltet Mühsam
CDI Unterstützt Standard Standard ab v25.10 Sauber

Für eine Docker-Installation auf einem einzelnen Server funktioniert Legacy nach wie vor gut. Sobald Kubernetes, Rootless-Betrieb oder mehrere Nutzer ins Spiel kommen, wechseln Sie zu CDI — dorthin fließen NVIDIAs Investitionen. Die Migration ist nicht invasiv: Toolkit installieren, CDI-Spezifikation erzeugen und --gpus all durch --device=nvidia.com/gpu=all ersetzen. Beide Modi können nebeneinander bestehen.

GPU-Passthrough — was --gpus all tatsächlich tut

Wenn Sie docker run --gpus all my-image ausführen, liest der Runtime-Hook NVIDIA_VISIBLE_DEVICES / NVIDIA_DRIVER_CAPABILITIES, hängt /dev/nvidia* mit cgroup-Berechtigungen in den Container ein, bindet die .so Dateien des Host-Treibers per Bind-Mount ein und setzt LD_LIBRARY_PATH so, dass der Linker sie findet.

Was Sie dabei steuern:

docker run --gpus all ...                                     # alle GPUs
docker run --gpus '"device=0,1"' ...                          # nach Index
docker run --gpus '"device=GPU-abc123..."' ...                # nach UUID
docker run --gpus all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility ...
docker run --device=nvidia.com/gpu=0 --device=nvidia.com/gpu=1 ...  # CDI

Für einen 8-GPU-Server mit tensor-parallelem vLLM verwenden Sie --gpus all. Auf einer Mehrmandanten-Maschine, auf der Nutzer 4-GPU-Slices erhalten, pinnen Sie per UUID — index-basiertes Pinnen bricht, sobald Sie neu verkabeln.

NGC-Container — wann sie sinnvoll sind

NVIDIAs NGC-Katalog (nvcr.io) liefert Images für PyTorch, TensorRT, TensorRT-LLM, Triton und weitere. Groß (5–15 GB), aber getestet und mit cuDNN-, NCCL- und CUDA-Runtime-Kombinationen ausgeliefert, die NVIDIA selbst qualitätsgesichert hat. Stand Mai 2026:

Image Enthält
nvcr.io/nvidia/pytorch:25.12-py3 PyTorch 2.9.1 + CUDA 13.0 + cuDNN 9 + NCCL
nvcr.io/nvidia/tritonserver:25.12-py3 Triton + Backends für Python / ONNX / TensorRT / vLLM
nvcr.io/nvidia/tensorrt-llm/release:0.x TensorRT-LLM-Build, optimierte Engines, NCCL
nvcr.io/nvidia/tensorrt:25.08-py3 TensorRT C++ / Python, ONNX-Parser

Die Tags lauten <year>.<month>-py3, monatlich geschnitten. Kein exaktes Upstream — gepatcht und neu gebaut —, aber nah dran.

Der ehrliche Fall für NGC: Wenn Sie TensorRT-LLM oder Triton betreiben, nehmen Sie das NGC-Image. Die Arbeit, cuDNN, NCCL, TensorRT und CUDA aufeinander abzustimmen, ist damit erledigt. Für Upstream-PyTorch oder vLLM sind die öffentlichen Images (pytorch/pytorch:..., vllm/vllm-openai:...) kleiner und schneller aktualisiert — NGC ist Overkill.

MIG — und warum es für die Kentino-Produktlinie keine Rolle spielt

MIG teilt eine einzelne GPU in bis zu sieben isolierte Slices auf, jedes mit eigenem Speicher, eigener Rechenleistung und eigener Fehlerdomäne. Nützlich für mandantenfähige Inferenz — fünf Nutzer erhalten je ein Siebtel einer H100 mit harter Isolation.

MIG steht auf Consumer-Karten (RTX 5090, 4090) und auf Workstation-Blackwell-Karten (RTX Pro 6000) nicht zur Verfügung. Es bleibt den Datacenter-SKUs vorbehalten — H100, H200, A100, B100, B200, GB200. Kentino bezieht keine Datacenter-GPUs im SXM-Formfaktor, MIG kommt daher in keinem Kentino-Build vor.

Der Ersatz auf Consumer- und Workstation-Karten ist MPS (Multi-Process Service) — mehrere Prozesse teilen sich den Compute-Scheduler der GPU. Keine harte Isolation wie bei MIG (ein einziger fehlerhafter Prozess kann das Gerät per OOM abschießen), doch für vertrauenswürdige mandantenfähige Inferenz funktioniert es und kostet nichts. Wenn Sie MIG wirklich brauchen, brauchen Sie die Datacenter-SKU-Linie über einen anderen Integrator.

Troubleshooting — die Fehler, die jeden treffen

CUDA error: no kernel image is available for execution on the device (Fehler 209). Die CUDA-Runtime des Containers enthält keine Kernel für die Compute Capability Ihrer GPU — meist ein CUDA-12.4-Image auf einer Blackwell-Karte (sm_120), die mindestens 12.8 benötigt. Lösung: neueres Image oder Build mit der passenden TORCH_CUDA_ARCH_LIST.

CUDA error: forward compatibility was attempted on non supported HW (Fehler 100). Der Host-Treiber ist älter, als die Runtime im Container es verlangt. Lösung: Host-Treiber aktualisieren — und zwar aus NVIDIAs Repository, nicht aus Ubuntus veralteter Paketversion.

Failed to initialize NVML: Driver/library version mismatch. Treiber per apt aktualisiert, aber nicht neu gestartet; das Kernelmodul ist alt, der Userspace neu. Lösung: Neustart. (Falls das nicht geht, entladen Sie die nvidia-Module mit rmmod und laden sie mit modprobe wieder — ein Neustart ist jedoch sicherer.)

nvidia-container-cli: initialization error: nvml error: driver not loaded. Das Toolkit ist installiert, aber das Kernelmodul des Treibers ist nicht geladen. Meist eine Neuinstallation, bei der nvidia-smi bereits auf dem Host fehlschlägt. Bringen Sie zuerst den Host in Ordnung, dann den Container.

OCI runtime exec failed: ... no such file or directory bei --gpus all. Der Runtime-Hook ist bei Docker nicht registriert. Führen Sie sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker erneut aus. Hilft das nicht, prüfen Sie /etc/docker/daemon.json auf einen "runtimes" Block.

Selbst bauen oder vorgefertigt nehmen

PyTorch, vLLM, llama.cpp, FlashAttention — für alle gibt es vorgefertigte Wheels und Images. Bauen Sie nur dann aus dem Quellcode, wenn Sie eine noch nicht veröffentlichte Funktion brauchen, eine Compute Capability nutzen, die die Upstream-Wheels nicht abdecken, oder gegen ein eigenes CUDA bzw. cuDNN kompilieren. Ein PyTorch aus dem Quellcode dauert auf EPYC 30–90 Minuten und bringt ohne eigene CMake-Flags keinerlei Performancegewinn. Source-Builds sind die Antwort auf ein konkretes Problem, nicht der Normalfall.

Wie es weitergeht

Für einen von Kentino gebauten Server von Grund auf:

  1. Ubuntu LTS installieren, den Treiber pinnen gemäß L01.
  2. Installieren Sie cuda-runtime-13-0 (das vollständige Toolkit können Sie überspringen, sofern Sie nicht selbst kompilieren).
  3. Installieren Sie libcudnn9-cuda-13 über apt — oder überspringen Sie es, wenn Sie vollständig containerisiert arbeiten.
  4. Installieren Sie nvidia-container-toolkit, konfigurieren Sie Docker und machen Sie einen Smoke-Test mit docker run --rm --gpus all nvidia/cuda:13.0.0-base-ubuntu24.04 nvidia-smi.
  5. Holen Sie das Image für Ihren Workload: vllm/vllm-openai:latest, nvcr.io/nvidia/pytorch:25.12-py3, oder nvcr.io/nvidia/tritonserver:25.12-py3.
  6. Starten Sie mit --gpus all, oder migrieren Sie jetzt zu CDI, wenn Mehrbenutzerbetrieb, Rootless oder Kubernetes absehbar sind.
  7. apt-mark hold für den Treiber — und niemals apt-get dist-upgrade auf einem laufenden Server.

L03 behandelt Kernel-Tuning, L04 behandelt die Dateisystem-Wahl für Modell-Storage und Checkpoint-Durchsatz, und L05 behandelt den Monitoring-Stack (Prometheus, Grafana, DCGM-Exporter). Wenn nvidia-smi heute auf Ihrer Maschine in einem Container läuft, haben Sie 80% des Weges hinter sich.


Dies ist Teil des Kentino Wiki, einer Referenzreihe über KI-Rechenleistung, Robotik und die Systeme, die beides verbinden. Kommentare und Korrekturen gerne an info@kentino.com.