Page cover

NVIDIA GPUs sur Kubernetes

Ajouter un GPU à Kubernetes m'a permis de jouer avec Jellyfin et LLaMA sur un serveur Kubernetes qui se trouve sur un ordinateur à la maison mais les étapes sont reproduisible dans le cloud.

Je couvrirais les étapes d'installation et de configuration suivantes:

  • Kubernetes

  • Container Runtime

  • Software

  • GPU

Pour l'utilisation du GPU sur nos POD, le containeur devra inclure les les logiciels/drivers pour l'utilisation de CUDA.

Comment Kubernetes sait quel POD à besoin de GPUs?

Dans Kubernetes, les pods necessitant des GPU sont identifié par les demandes ressources et les limites dans la coniguration de pod

Ressources étendue

Ressources étendue: Les GPU ne sont pas reconnus nativement par Kubernetes mais sont considéré comme des "ressources étendues" necessitant donc une configuration spéciale pour leur utilisation.

Runtime Class

Runtime Class: Pour utiliser des ressources spécifiquement comme les GPU NVIDIA, Kubernetes peut etre configuré pour utiliser une classe d'éxecution spécifique ('runtimeClassName'). Cela permet d'utiliser le runtime de conteneur NVIDIA qui est optimisé pour les GPU.

spec:
  runtimeClassName: nvidia   # Utiliser le runtime de conteneur NVIDIA

Demandes et limites de ressources

Demandes et limites de ressources: La spécification du pod (spec) utilise des demandes et des limites de ressources pour déclarer explicitement qu'un certain nombre de GPU sont nécessaires. Pour les GPU NVIVIA cela est généralement défini comme nvidia.com/gpu

  containers:
    - name: mon-conteneur-gpu
      image: mon-image-gpu
      resources:
        limits:
          nvidia.com/gpu: 1  # Demande 1 GPU

NodeSelector

Cet attribut aide à planifier les pods sur les noeuds qui ont les GPU requis. Il garanti que le pod s'exécute sur un nœud capable de répondre aux exigences de GPU

nodeSelector:
  kubernetes.io/hostname: nom-du-noeud-gpu  # Remplacez par le nom de noeud approprié

Tolérance

Il est également courant de voir NoSchedule dans la configuration. Il s'agit d'empecher l'eceution de charges de travail qui n'ont pas explicitement besoin de GPU. (Taints and toleration docs)

spec:
  tolerations:
    - key: nvidia.com/gpu
      operator: Exists
      effect: NoSchedule

NVIDIA GPU Operator

Les fonctionnalités des GPU NVIDIA sont géré automatiquement par le NVIDIA GPU Operator, cela facilite grandement l'utilisation des cartes graphiques GPU dans un environnement Kubernetes.

  1. NVIDIA GPU Operator : L'opérateur s'occupe automatiquement de plusieurs tâches complexes :

    • Installation des pilotes : Il peut installer tout seul les logiciels nécessaires pour que les GPU fonctionnent correctement sur les ordinateurs (node).

    • Configuration du système : Il configure le système pour que les conteneurs puissent utiliser efficacement les GPU.

    • Étiquetage des nœuds : Il ajoute des labels sur les nodes pour indiquer quels nœuds ont des GPU et combien.

  2. NVIDIA device Plugin : C'est une composante qui:

    • Détecte les GPU : il detecte automatiquement le nombre de GPU disponible sur chaque node et informe Kubernetes de savoir combien de GPU sont libres ou utilisés.

    • Surveille la santé des GPU : Il suit l'état de fonctionnement des GPU pour s'assurer que tout fonctionne bien.

    • Exécution de conteneurs avec GPU : Il permet de lancer des applications qui nécessitent des GPU pour fonctionner plus rapidement, par exemple pour traiter des images ou des calculs complexes.

  3. Planification et exécution : Le cluster Kubernetes a programmé des taches sur les nodes pour être prêts à utiliser les GPU et a donné les instructions nécessaires pour utiliser ces ressources GPU de manière optimale.

Configuration NVIDIA sur Kubernetes

Vérifier la présence de la carte GPU

Utiliser lspci pour faire apparaitre les informations PCI sur votre système et ainsi vérifier la présence de votre carte GPU.

# list all PCI devices with the text NVIDIA
sudo lspci | grep NVIDIA

Vous devriez voir:

sudo lspci | grep NVIDIA
01:00.0 VGA compatible controller: NVIDIA Corporation TU102 [GeForce RTX 2080 Ti Rev. A] (rev a1)
01:00.1 Audio device: NVIDIA Corporation TU102 High Definition Audio Controller (rev a1)
01:00.2 USB controller: NVIDIA Corporation TU102 USB 3.1 Host Controller (rev a1)
01:00.3 Serial bus controller: NVIDIA Corporation TU102 USB Type-C UCSI Controller (rev a1)

Vérification des drivers GPU NVIDIA

Utiliser la recherche sur le site de téléchargement des drivers NVIDIA pour trouver le dernier recommandé pour votre carte.

Par exemple pour ma 2080TI

Version

550.78

Release Date

2024.4.25

Operating System

Linux 64-bit

Language

English (US)

File Size

292.67 MB

Ce qui veut dire que l'on doit prendre la version 550+

Installation des drivers GPU

Il existe plusieurs methode pour installer les drivers sur mon serveur Ubuntu 24.04 LTS:

  • Officiel Ubuntu NVIDIA drivers via ubuntu-drivers install (lien)

  • Officiel NVIDIA driver via .run file (lien)

  • Non officiel version driver NVIDIA via ppa:graphics-drivers/ppa (lien)

Dans mon cas pour notre installation nous utiliserons l'option (ppa)

Ajouter le repo PPA et installer la version de driver trouvé sur le site officiel.

# add ppa:graphics-driver repo to apt
sudo add-apt-repository ppa:graphics-drivers/ppa --yes

# update apt content list
sudo apt update

# install driver
sudo apt install nvidia-driver-550

Tester la version du driver installé avec la commande nvidia-smi

# get the driver version
nvidia-smi --query-gpu=driver_version --format=csv,noheader

Dans mon cas j'ai comme retour 550.78

Pour voir la liste des packages installé utilisé dpkg -l avec "nvidia" ou "550"

dpkg -l | grep nvidia
# or
dpkg -l | grep 535

Vérifier les modules kernel installé en utilisant lsmod qui permet de lister ce qui se trouve dans /proc/modules

# Show the status of driver modules in the Linux Kernel
lsmod | grep nvidia

Si tout semble bon vous devriez avoir:

# lsmod | grep nvidia
nvidia_uvm           4931584  12
nvidia_drm            122880  0
nvidia_modeset       1355776  1 nvidia_drm
nvidia              54239232  41 nvidia_uvm,nvidia_modeset
i2c_nvidia_gpu         12288  0
i2c_ccgx_ucsi          12288  1 i2c_nvidia_gpu
video                  73728  1 nvidia_modeset

Vérifiez le fichier de version du pilote du kernel:

cat /proc/driver/nvidia/version
# cat /proc/driver/nvidia/version
NVRM version: NVIDIA UNIX x86_64 Kernel Module  550.78  Sun Apr 14 06:35:45 UTC 2024
GCC version:  gcc version 13.2.0 (Ubuntu 13.2.0-23ubuntu4)

Vérifiez le fichier de périphérique NVIDIA trouvé:

# any device files (I/O sys calls)
ls /dev/ | grep 'nvidia[0-9]\+'

Votre serveur maintenant a bien un GPU NVIDIA d'installé et fonctionnel si le retour de la commande est:

# ls /dev/ | grep 'nvidia[0-9]\+'
nvidia0

Installation du Container Toolkit NVIDIA

Vous pouvez trouver le guide d'installation officiel de NVIDIA

# add nvidia-container-toolkit repo to apt sources
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

# update apt content
sudo apt update

# install container toolkit
sudo apt install -y nvidia-container-toolkit

Mon environnement Kubernetes étant sur containerd, nous avons besoin de mettre à jour la configuration runtime classes.

Toujours depuis le guide NVIDIA sur la configuration

# options: --dry-run
sudo nvidia-ctk runtime configure --runtime=containerd

Si votre Kubernetes porte le service containerd non comme K3S ou RKE2 vous devrez relancer le service.

sudo systemctl restart containerd

# Verifier que le service est up
sudo systemctl status containerd

Valider en vérifiant que nvidia runtime existe bien dans la config

sudo cat /etc/containerd/config.toml | grep "containerd.runtimes.nvidia."

le résultat doit être:

# sudo cat /etc/containerd/config.toml | grep "containerd.runtimes.nvidia."
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]

Installation de NVIDIA GPU Operator

Nous devons maintenant installer le NVIDIA GPU Operator avec helm.

Vous pouvez installer helm en suivant le guide officiel

Ajouter le repo helm et faire un update:

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \
   && helm repo update

Déployer NVIDIA GPU Operator sur votre serveur, par défaut il installe NVIDIA Container Toolkit et NVIDIA drivers comme des container sur le node. Les valeurs sont misent à false car nous venons de le faire.

helm install --wait gpu-operator \
     -n gpu-operator --create-namespace \
      nvidia/gpu-operator \
      --set driver.enabled=false \
      --set toolkit.enabled=false

Vérifier le déploiement des pods:

# ensure nothing on kubernetes is wonky
kubectl get pods -n gpu-operator | grep -i nvidia

fini vous devriez avoir:

kubectl get pods -n gpu-operator | grep -i nvidia
nvidia-cuda-validator-nfpqp                                   0/1     Completed   0
nvidia-dcgm-exporter-9jb4j                                    1/1     Running     0
nvidia-device-plugin-daemonset-ljk4c                          2/2     Running     0
nvidia-operator-validator-wzc5l                               1/1     Running     0

Valider l'installation avec cette comande:

kubectl -n gpu-operator logs deployment/gpu-operator | grep GPU

vous devez avoir comme resultat Number of nodes with GPU label","NodeCount":1 ou 1 est le nombre de node avec une GPU

S'il donne comme resulat 0 il y a une erreur, vous pouvez debugger avec la comande:

kubectl get events -n gpu-operator --sort-by='.lastTimestamp'

Pour finir, mettez en place un pod sur votre cluster pour verifier que votre integration NVIDIA fonctionne:

# EXPORT NODE NAME!
export NODE_NAME=$(kubectl get nodes -l nvidia.com/gpu.present=true -o custom-columns=NAME:.metadata.name --no-headers | head -n 1
)

cat <<EOF | kubectl create -f -     
apiVersion: batch/v1
kind: Job
metadata:
  name: test-job-gpu
spec:
  template:
    spec:
      runtimeClassName: nvidia
      containers:
      - name: nvidia-test
        image: nvidia/cuda:12.0.0-base-ubuntu22.04
        command: ["nvidia-smi"]
        resources:
          limits:
            nvidia.com/gpu: 1
      nodeSelector:
        kubernetes.io/hostname: ${NODE_NAME}
      restartPolicy: Never
EOF

regarder les logs:

kubectl logs job/test-job-gpu

vous devez avoir ce résultat:

Félicitation 🎉🎉 vous avez un GPU de configuré sur une cluster Kubernetes.

Liens utiles

Mis à jour