Utilisation Avancée de Docker avec les GPU NVIDIA

Gestion des Conteneurs avec Accès aux GPU NVIDIA

Ce document détaille l'utilisation des outils nvidia-docker et nvidia-docker-plugin pour intégrer de manière transparente les capacités des GPU NVIDIA dans les environnements conteneurisés Docker. Ces outils simplifient le déploiement d'applications gourmandes en calcul sur des architectures hétérogènes.

Installation de nvidia-docker

L'installation de base de nvidia-docker peut être effectuée via un paquet .deb :

dpkg -i nvidia-docker_1.0.1-1_amd_64.deb

Avantages de l'intégration NVIDIA Docker

  • Reproductibilité : Assure des environnements d'exécution cohérents.
  • Facilité de déploiement : Simplifie la mise en place de workflows GPU.
  • Isolation des ressources : Permet un contrôle précis de l'accès aux GPU.
  • Compatibilité multi-pilotes : Fonctionne sur diverses versions de pilotes NVIDIA.
  • Dépendance minimale : Nécessite uniquement l'installation du pilote NVIDIA sur l'hôte.
  • Autonomie : Facilite l'exécution d'applications GPU sans configuration complexe.
  • Collaboration améliorée : Partage simplifié d'environnements de développement.

Présentation de nvidia-docker

nvidia-docker agit comme une surcouche légère pour Docker, remplaçant la ligne de commande habituelle. Son rôle est de détecter automatiquement et de configurer l'accès aux GPU pour les conteneurs. Pour les utilisateurs avancés, il est possible de spécifier une commande Docker alternative via la variable d'environnement NV_DOCKER :

# Utilisation d'une commande Docker personnalisée avec nvidia-docker
NV_DOCKER='sudo docker -D' nvidia-docker <options_docker> <commande_docker> <arguments_docker>
</arguments_docker></commande_docker></options_docker>

Il est important de noter que nvidia-docker modifie uniquement la commande d'exécution du conteneur et la création des commandes Docker. Le processus de construction des images Docker (docker build) n'est pas affecté et ne peut pas exécuter de code GPU.

Isolation des GPU

L'accès aux GPU peut être contrôlé finement à l'aide de la variable d'environnement NV_GPU. Elle accepte une liste d'identifiants de GPU séparés par des virgules, ces identifiants pouvant être des indices numériques ou des UUIDs.

  • L'indexation des GPU suit celle rapportée par nvidia-smi ou l'ordre défini par CUDA_DEVICE_ORDER=PCI_BUS_ID.
  • Par défaut, tous les GPU sont accessibles.

Exemples d'isolation :

# Accès aux GPU avec les indices 0 et 1
NV_GPU='0,1' nvidia-docker <options_docker> <commande_docker> <arguments_docker>

# Accès aux GPU via leurs UUIDs
NV_GPU='GPU-836c0c09,GPU-b78a60a' nvidia-docker <options_docker> <commande_docker> <arguments_docker>
</arguments_docker></commande_docker></options_docker></arguments_docker></commande_docker></options_docker>

Configuration Locale et Distante

Exécution Locale

Si nvidia-docker-plugin est installé sur le système hôte, aucune configuration supplémentaire n'est requise. nvidia-docker communiquera automatiquement avec le plugin pour accéder aux GPU.

Exécution Distante

Pour une utilisation à distance, nvidia-docker-plugin doit être en cours d'exécution sur l'hôte distant. La cible de l'hôte distant peut être spécifiée via les variables d'environnement DOCKER_HOST ou NV_HOST.

  • NV_HOST a priorité sur DOCKER_HOST.
  • Si NV_HOST n'est pas défini mais que DOCKER_HOST l'est, NV_HOST utilisera l'emplacement défini dans DOCKER_HOST avec le protocole HTTP sur le port 3476.

La syntaxe de NV_HOST est : [(http|ssh)://][<utilisateur_ssh>@][<hôte>][:<port_ssh>][:<port_http>]

  • Le protocole HTTP requiert que le plugin écoute sur une interface accessible (par défaut, il écoute uniquement sur localhost).
  • Le protocole SSH nécessite des identifiants SSH valides (mot de passe ou clé privée).

Exemples de configuration distante :

# Exécution sur un hôte distant via HTTP
DOCKER_HOST='10.0.0.1:' nvidia-docker run cuda

# Exécution sur un hôte distant via SSH
NV_HOST='ssh://10.0.0.1:' nvidia-docker -H 10.0.0.1: run cuda

# Exécution distante via SSH avec utilisateur et ports personnalisés
DOCKER_HOST='10.0.0.1:' NV_HOST='ssh://user@10.0.0.1:22:80' nvidia-docker run cuda

Le Plugin nvidia-docker-plugin

Description

nvidia-docker-plugin est un plugin Docker Engine conçu pour simplifier le déploiement de conteneurs sensibles aux GPU dans des environnements variés. Il fonctionne comme un démon qui détecte les fichiers du pilote NVIDIA et les périphériques GPU sur l'hôte, et répond aux requêtes d'installation de volumes provennat du démon Docker.

Le plugin expose également une API REST pour interroger les informations GPU et générer des paramètres Docker.

Utilisation et Configuration du Plugin

Le démon du plugin peut être configuré via des arguments en ligne de commande :

Usage de nvidia-docker-plugin :
  -d string
        Répertoire de stockage des volumes (défaut : "/var/lib/nvidia-docker/volumes")
  -l string
        Adresse d'écoute du serveur (défaut : "localhost:3476")
  -s string
        Chemin vers le socket du plugin (défaut : "/run/docker/plugins")
  -v    Afficher les informations de version du plugin

Pour les installations via paquets binaires, les configurations peuvent être modifiées dans le fichier /etc/default/nvidia-docker ou via des fichiers d'override systemd.

Après le lancement du plugin, nvidia-docker peut communiquer avec lui pour obtenir les informations nécessaires à la conteneurisation. Un redémarrage du plugin est nécessaire après une mise à jour du pilote NVIDIA.

API REST du Plugin

L'API REST est accessible par défaut sur le port 3476 en local. Les points d'accès (endpoints) sont les suivants (le préfixe de version peut être omis pour accéder à la dernière version) :

Version 1.0

  • GET /v1.0/gpu/info, /v1.0/gpu/info/json : Récupère des informations détaillées sur les périphériques GPU (similaire à nvidia-smi -q). Les réponses sont au format texte ou JSON.
  • GET /v1.0/gpu/status, /v1.0/gpu/status/json : Interroge l'état actuel des périphériques GPU (similaire à nvidia-smi). Les réponses sont au format texte ou JSON.
  • GET /v1.0/docker/cli, /v1.0/docker/cli/json : Génère les paramètres de ligne de commande pour docker run ou docker create. Accepte les paramètres de requête dev (pour les GPU) et vol (pour les volumes). Utile si vous n'utilisez pas le wrapper nvidia-docker.
  • GET /v1.0/mesos/cli : Récupère les paramètres de ligne de commande pour le lancement d'un agent Mesos. Les informations sur les périphériques sont compressées et encodées en zlib/base64 (RFC 6920).

Limitations Connues

  1. Cohérence des partitions : Le répertoire des volumes du plugin Docker doit être sur la même partition que celle où les pilotes NVIDIA sont installés. Ceci est dû à la nécessité de créer des liens physiques vers certains fichiers du pilote. Des solutions alternatives incluent l'installation des pilotes dans un emplacement différent ou la modification du répertoire des volumes du plugin (via l'option -d). Il est déconseillé de placer le répertoire des volumes du plugin dans la même structure de répertoire que les pilotes NVIDIA (par ex. /usr/lib) pour éviter les conflits lors des mises à jour.

Architecture Interne et Fonctionnement

Gestion des Pilotes NVIDIA

Les Défis

L'exécution d'applications GPU nécessite l'installation des pilotes NVIDIA, qui comprennent des modules noyau et des bibliothèques utilisateur. Ces bibliothèques sont souvent liées à des versions spécifiques de pilotes, comme indiqué par des noms de fichiers incluant des numéros de version.

Une approche initiale consistant à installer les bibliothèques utilisateur à l'intérieur des conteneurs échoue car la version des bibliothèques doit correspondre exactement à celle du module noyau de l'hôte. Comme tous les conteneurs partagent le noyau de l'hôte, cela rend les images Docker non portables et invalide l'un des avantages principaux de Docker. La solution consiste à rendre les images indépendantes de la version du pilote hôte.

Les distributions des pilotes NVIDIA varient, et l'emplacement des fichiers peut différer. Les bibliothèques utilisateur doivent être rendues accessibles aux conteneurs via des montages de volumes.

Approche avec nvidia-docker

nvidia-docker analyse le système pour localiser les bibliothèques nécessaires, en tenant compte des conflits potentiels (par exemple, plusieurs versions de bibliothèques OpenGL). Il crée ensuite un volume Docker nommé contenant des liens physiques vers ces bibliothèques. En cas d'échec des liens physiques, une copie est utilisée comme solution de repli.

Ce volume est géré par le démon nvidia-docker-plugin, qui implémente l'API des plugins de volume de Docker. nvidia-docker ajoute automatiquement les paramètres de volume appropriés à la commande Docker.

$ docker volume inspect nvidia_driver_375.66
[
    {
        "Driver": "nvidia-docker",
        "Labels": null,
        "Mountpoint": "/var/lib/nvidia-docker/volumes/nvidia_driver/375.66",
        "Name": "nvidia_driver_375.66",
        "Options": {},
        "Scope": "local"
    }
]

Alternatives Manuelles

Il est possible d'intégrer manuellement les volumes sans utiliser le wrapper nvidia-docker :

$ docker run --volume-driver=nvidia-docker --volume=nvidia_driver_375.66:/usr/local/nvidia:ro

Une autre méthode consiste à créer le volume nommé manuellement :

$ docker volume create --name=nvidia_driver_375.66 -d nvidia-docker

Sans l'utilisation des plugins de volume, il faut localiser manuellement les fichiers du pilote (via ldconfig -p) et les monter dans le conteneur. L'utilisation de noms de volume suffixés par la version du pilote est recommandée pour éviter les incohérences.

Isolation des Périphériques GPU

Les Défis

Les GPU sont représentés comme des fichiers périphériques dans /dev (par exemple, /dev/nvidia0). Docker permet d'exposer des périphériques spécifiques à un conteneur via l'option --device.

La difficulté réside dans la cartographie correcte entre l'ordre des périphériques tel que rapporté par nvidia-smi et les numéros mineurs des fichiers périphériques. De plus, le module noyau nvidia_uvm doit être chargé pour que /dev/nvidia-uvm soit créé, ce qui peut nécessiter une intervention manuelle.

$ ls -l /dev/nvidia*
crw-rw-rw- 1 root root 195,   0 Jul 10 10:03 /dev/nvidia0
# ... autres périphériques nvidia

nvidia-smi peut rapporter un ordre différent de celui des numéros mineurs des fichiers périphériques :

$ nvidia-smi -q
GPU 0000:05:00.0
 Minor Number: 3
# ...
GPU 0000:06:00.0
 Minor Number: 2

Approche avec nvidia-docker

nvidia-docker utilise la bibliothèque NVML pour énumérer les GPU et obtenir leurs numéros mineurs correspondants. La variable NV_GPU permet de spécifier quels GPU (par index ou UUID) doivent être rendus accessibles au conteneur.

$ NV_GPU=0,1 nvidia-docker run -ti nvidia/cuda nvidia-smi

Pour charger le module nvidia_uvm, la commande nvidia-modprobe -u -c = 0 est exécutée sur l'hôte lors du démarrage du plugin.

Alternatives Manuelles

L'exposition manuelle des périphériques est possible :

$ docker run --device=/dev/nvidiactl --device=/dev/nvidia-uvm --device=/dev/nvidia0

Cette approche doit être combinée avec le montage des bibliothèques du pilote utilisateur. L'utilisation de NVML est recommandée pour obtenir une cartographie précise des GPU. L'environnement CUDA_VISIBLE_DEVICES doit être géré avec soin.

Vérification des Images pour l'Utilisation GPU

Les Défis

Il est difficile de déterminer de manière universelle si une image Docker est conçue pour utiliser le GPU. De plus, il faut s'assurer de la compatibilité entre les versions des pilotes NVIDIA de l'hôte et les versions CUDA utilisées dans l'image.

Approche avec nvidia-docker

nvidia-docker présume que les images basées sur la série nvidia/cuda (disponibles sur Docker Hub) sont destinées à un usage GPU. Ces images possèdent des labels spécifiques, comme com.nvidia.volumes.needed, indiquant la nécessité de monter les volumes de pilotes.

La compatibilité des versions est vérifiée via le label com.nvidia.cuda.version présent dans les images CUDA. Une comparaison est effectuée avec la version maximale supportée par le pilote hôte (obtenue via cudaDriverGetVersion). Si le pilote est trop ancien, une erreur est générée avant le démarrage du conteneur :

$ nvidia-docker run --rm nvidia/cuda
nvidia-docker | 2016/04/21 21:41:35 Error: unsupported CUDA version: driver 7.0 < image 7.5

Alternatives

Pour répliquer ce comportement sans nvidia-docker, il faudrait analyser manuellement les labels des images et vérifier la compatibilité des versions des pilotes au préalable.

Il est conseillé de réutiliser les mêmes labels pour les images CUDA personnalisées afin de maintenir la compatibilité.

Étiquettes: Docker NVIDIA GPU conteneurisation pilote nvidia

Publié le 22 juillet à 17h24