Veröffentlicht am

GPU Workloads auf Kubernetes: NVIDIA Device Plugin einrichten

Teilen:
Authors

GPU Workloads auf Kubernetes: NVIDIA Device Plugin und Scheduling

TL;DR

  • GPU-Workloads auf Kubernetes erfordern das NVIDIA Device Plugin (oder den GPU Operator) auf jedem GPU-Node
  • GPUs werden als Extended Resources (nvidia.com/gpu) angefordert -- sie sind nicht teilbar (1 GPU = 1 Container, ohne MIG/Time-Slicing)
  • Node Affinity und Taints/Tolerations sorgen dafuer, dass GPU-Pods nur auf GPU-Nodes laufen
  • Monitoring ueber DCGM Exporter + Prometheus zeigt GPU-Auslastung, Temperatur und Memory
  • Fuer Multi-GPU-Training brauchen Sie spezielle Frameworks (PyTorch DDP, Horovod) -- Kubernetes allein verteilt kein Training

Warum GPUs auf Kubernetes?

Wer ML-Modelle trainiert oder GPU-beschleunigte Inferenz betreibt, steht vor der Frage: Bare-Metal-Server mit manueller Verwaltung oder Kubernetes als Orchestrator? Kubernetes bietet hier klare Vorteile:

  • Scheduling: Automatische Zuweisung von GPU-Ressourcen an Jobs
  • Multi-Tenancy: Mehrere Teams teilen sich einen GPU-Pool mit ResourceQuotas
  • Reproducibility: GPU-Jobs als deklarative YAML-Specs versionierbar
  • Integration: GPU-Training laesst sich in CI/CD-Pipelines (Argo Workflows, Kubeflow) einbinden

Die Herausforderung: GPUs sind keine Standard-Kubernetes-Ressourcen wie CPU oder Memory. Sie benoetigen einen Device Plugin, der die GPUs dem Kubelet bekannt macht.

Weitere Hintergruende zu Kubernetes fuer ML finden Sie in unserem Artikel zu MLOps auf Kubernetes.


Architektur: Wie Kubernetes GPUs verwaltet

Die Kette ist: NVIDIA-Treiber auf dem Host */} NVIDIA Container Toolkit (frueher nvidia-docker) */} NVIDIA Device Plugin als DaemonSet */} kubelet erkennt GPUs als Extended Resources */} Scheduler kann Pods auf GPU-Nodes zuweisen.


Option 1: NVIDIA Device Plugin direkt installieren

Das Device Plugin ist ein DaemonSet, das auf jedem GPU-Node laeuft und die verfuegbaren GPUs als Extended Resources registriert.

Voraussetzungen

  • NVIDIA-Treiber auf den Nodes installiert (z.B. 535.x oder neuer)
  • NVIDIA Container Toolkit installiert und als Default-Runtime konfiguriert
  • Kubernetes 1.26+

DaemonSet deployen

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule
      priorityClassName: system-node-critical
      containers:
        - name: nvidia-device-plugin-ctr
          image: nvcr.io/nvidia/k8s-device-plugin:v0.17.0
          env:
            - name: FAIL_ON_INIT_ERROR
              value: "false"
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: device-plugin
              mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins
# Oder direkt via kubectl:
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.17.0/deployments/static/nvidia-device-plugin.yml

# Pruefen, ob GPUs erkannt werden:
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, gpus: .status.allocatable["nvidia.com/gpu"]}'

Option 2: NVIDIA GPU Operator (empfohlen)

Der GPU Operator automatisiert die gesamte Kette: Treiber-Installation, Container Toolkit, Device Plugin, DCGM Exporter und optional MIG-Konfiguration. Das ist der empfohlene Weg, wenn Sie nicht jeden Node manuell vorbereiten moechten.

# Helm Repository hinzufuegen
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update

# GPU Operator installieren
helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator \
  --create-namespace \
  --set driver.enabled=true \
  --set toolkit.enabled=true \
  --set devicePlugin.enabled=true \
  --set dcgmExporter.enabled=true
# Status pruefen
kubectl get pods -n gpu-operator

# Erwartete Pods:
# nvidia-driver-daemonset-*
# nvidia-container-toolkit-daemonset-*
# nvidia-device-plugin-daemonset-*
# nvidia-dcgm-exporter-*
# gpu-feature-discovery-*

Der GPU Operator eignet sich besonders fuer Cloud-Umgebungen (EKS, AKS, GKE), wo Nodes dynamisch hinzukommen.


GPU-Pods deployen

Einfacher GPU-Pod

apiVersion: v1
kind: Pod
metadata:
  name: gpu-test
spec:
  restartPolicy: Never
  containers:
    - name: cuda-test
      image: nvcr.io/nvidia/cuda:12.3.1-base-ubuntu22.04
      command: ["nvidia-smi"]
      resources:
        limits:
          nvidia.com/gpu: 1
kubectl apply -f gpu-test.yaml
kubectl logs gpu-test
# Sollte die GPU-Informationen anzeigen (Modell, Memory, Treiber-Version)

Wichtig: nvidia.com/gpu wird nur unter limits angegeben. Kubernetes setzt requests automatisch gleich limits fuer Extended Resources. GPUs sind nicht ueberbuchbar.

ML-Training Job mit PyTorch

apiVersion: batch/v1
kind: Job
metadata:
  name: pytorch-training
spec:
  backoffLimit: 2
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: trainer
          image: nvcr.io/nvidia/pytorch:24.01-py3
          command:
            - python
            - -c
            - |
              import torch
              print(f"CUDA available: {torch.cuda.is_available()}")
              print(f"GPU: {torch.cuda.get_device_name(0)}")
              # Ihr Training-Script hier
          resources:
            limits:
              nvidia.com/gpu: 1
              memory: 16Gi
              cpu: "4"
            requests:
              memory: 8Gi
              cpu: "2"
          volumeMounts:
            - name: data
              mountPath: /data
            - name: models
              mountPath: /models
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: training-data
        - name: models
          persistentVolumeClaim:
            claimName: model-storage

GPU-Scheduling mit Node Affinity und Taints

In einem gemischten Cluster (CPU- und GPU-Nodes) wollen Sie sicherstellen, dass GPU-Pods nur auf GPU-Nodes landen und CPU-Pods nicht versehentlich GPU-Nodes blockieren.

Taints auf GPU-Nodes setzen

# GPU-Nodes mit Taint versehen
kubectl taint nodes gpu-node-1 nvidia.com/gpu=present:NoSchedule
kubectl taint nodes gpu-node-2 nvidia.com/gpu=present:NoSchedule

# Labels setzen fuer Node Affinity
kubectl label nodes gpu-node-1 gpu-type=a100
kubectl label nodes gpu-node-2 gpu-type=t4

Pod mit Toleration und Node Affinity

apiVersion: v1
kind: Pod
metadata:
  name: gpu-inference
spec:
  tolerations:
    - key: nvidia.com/gpu
      operator: Equal
      value: present
      effect: NoSchedule
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: gpu-type
                operator: In
                values:
                  - a100
  containers:
    - name: inference
      image: your-inference-image:latest
      resources:
        limits:
          nvidia.com/gpu: 1

GPU-Typen: Wann welche GPU?

GPUVRAMTypischer EinsatzPreis (Cloud, ca.)
T416 GBInference, leichtes Training$0.35/h
A10G24 GBMittleres Training, Inference$1.00/h
A100 40GB40 GBGrosses Training, Multi-GPU$3.00/h
A100 80GB80 GBLLM-Training, grosse Modelle$4.50/h
H10080 GBState-of-the-Art Training$8.00/h

ResourceQuotas fuer GPU-Fair-Sharing

Wenn mehrere Teams GPUs teilen, verhindern ResourceQuotas, dass ein Team alle GPUs belegt:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-quota-team-ml
  namespace: team-ml
spec:
  hard:
    requests.nvidia.com/gpu: "4"
    limits.nvidia.com/gpu: "4"
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-quota-team-cv
  namespace: team-cv
spec:
  hard:
    requests.nvidia.com/gpu: "2"
    limits.nvidia.com/gpu: "2"

Mehr zu Multi-Tenancy und Resource Management: Kubernetes Multi-Tenancy und Kubernetes Resource Management.


GPU-Monitoring mit DCGM Exporter

Der DCGM (Data Center GPU Manager) Exporter stellt GPU-Metriken fuer Prometheus bereit. Der GPU Operator installiert ihn automatisch; bei manueller Installation:

helm install dcgm-exporter nvidia/dcgm-exporter \
  --namespace monitoring \
  --create-namespace \
  --set serviceMonitor.enabled=true

Wichtige Prometheus-Metriken

MetrikBeschreibung
DCGM_FI_DEV_GPU_UTILGPU-Auslastung in Prozent
DCGM_FI_DEV_MEM_COPY_UTILMemory-Auslastung in Prozent
DCGM_FI_DEV_GPU_TEMPGPU-Temperatur in Grad Celsius
DCGM_FI_DEV_POWER_USAGEStromverbrauch in Watt
DCGM_FI_DEV_FB_FREEFreier GPU-Speicher in MiB
DCGM_FI_DEV_FB_USEDBelegter GPU-Speicher in MiB

Fuer ein umfassendes Monitoring-Setup: GPU Monitoring auf Kubernetes und Kubernetes Monitoring und Observability.


Troubleshooting

# GPU nicht erkannt? Drei Checks:
# 1. Device Plugin laeuft?
kubectl get pods -n kube-system -l name=nvidia-device-plugin-ds

# 2. Node hat GPU-Kapazitaet?
kubectl describe node <gpu-node> | grep -A5 "Allocatable"

# 3. Pod haengt in Pending?
kubectl describe pod <gpu-pod> | tail -20
# Haeufige Ursachen: Insufficient nvidia.com/gpu, fehlende Toleration, ResourceQuota

Bei "CUDA out of memory": Kubernetes kann GPU-Memory nicht limitieren -- nvidia.com/gpu: 1 reserviert die gesamte GPU. Loesungen: Batch-Size reduzieren, Gradient Accumulation nutzen, oder auf eine GPU mit mehr VRAM wechseln.


Kostenoptimierung

  • Spot/Preemptible Nodes fuer Training-Jobs nutzen (bis 70% guenstiger)
  • GPU Time-Slicing aktivieren, wenn mehrere leichte Inferenz-Workloads eine GPU teilen sollen
  • Cluster Autoscaler konfigurieren, damit GPU-Nodes nur bei Bedarf hochgefahren werden
  • PriorityClasses nutzen, damit wichtige Jobs weniger wichtige verdraengen koennen

Weitere Tipps zur Kostenoptimierung: Kubernetes Autoscaling und Kosten sparen.


Fazit

GPU-Workloads auf Kubernetes zu betreiben ist kein Hexenwerk, erfordert aber ein sauberes Setup: NVIDIA Device Plugin oder GPU Operator, korrekte Taints und Tolerations, ResourceQuotas fuer Fair-Sharing und Monitoring mit DCGM Exporter. Der groesste Fehler ist, GPUs ohne Monitoring laufen zu lassen -- eine ungenutzte A100 bei 4 EUR/Stunde summiert sich schnell.


Sie planen GPU-Workloads auf Kubernetes oder moechten Ihre bestehende GPU-Infrastruktur optimieren? Erfahren Sie mehr ueber unsere Kubernetes Consulting-Angebote fuer ML/AI-Workloads.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen