Post

Construire un environnement de développement pour l'apprentissage profond avec NVIDIA Container Toolkit et Docker (2) - Configuration du runtime de conteneur pour l'utilisation du GPU, rédaction du Dockerfile et construction de l'image Docker

Cette série traite de la mise en place d'un environnement de développement pour l'apprentissage profond basé sur NVIDIA Container Toolkit et Docker en local, et de la configuration de SSH et Jupyter Lab pour l'utiliser comme serveur distant. Ce post est le deuxième article de la série, qui présente la méthode de configuration du runtime de conteneur pour l'utilisation du GPU, la rédaction du Dockerfile et la construction de l'image Docker.

Aperçu

Dans cette série, nous abordons le processus d’installation de NVIDIA Container Toolkit et Docker, et de construction d’un environnement de développement pour l’apprentissage profond en écrivant un Dockerfile basé sur les images CUDA et cuDNN fournies par le dépôt nvidia/cuda sur Docker Hub. Pour ceux qui en ont besoin, nous partageons le Dockerfile et l’image complétés à travers ce processus via GitHub et Docker Hub pour une utilisation libre, et fournissons en plus un guide de configuration SSH et Jupyter Lab pour une utilisation comme serveur distant.
La série se composera de 3 articles, et cet article que vous lisez est le deuxième de la série.

Nous procédons en supposant un système équipé d’une carte graphique NVIDIA prenant en charge CUDA dans un environnement Linux x86_64, et comme nous n’avons pas testé directement sur des distributions autres qu’Ubuntu ou Fedora, il peut y avoir de légères différences dans certains détails spécifiques.

Avant de commencer

Cet article fait suite à la Partie 1, donc si vous ne l’avez pas encore lue, il est recommandé de commencer par l’article précédent.

4. Configuration du runtime de conteneur

4-1. Exécution de la commande nvidia-ctk

1
sudo nvidia-ctk runtime configure --runtime=docker

Cette commande modifie le fichier /etc/docker/daemon.json pour permettre à Docker d’utiliser le NVIDIA Container Runtime.

4-2. Redémarrage du démon Docker

Redémarrez le démon Docker pour appliquer les modifications de configuration.

1
sudo systemctl restart docker

4-3. Vérification de la configuration correcte

Exécutez un conteneur CUDA d’exemple.

1
sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

Si un écran similaire à celui ci-dessous s’affiche, c’est un succès.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 555.58.02              Driver Version: 555.58.02      CUDA Version: 12.5     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3090        Off |   00000000:01:00.0  On |                  N/A |
|  0%   46C    P8             29W /  350W |     460MiB /  24576MiB |      2%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

5. Rédaction du Dockerfile

Nous écrivons un Dockerfile à utiliser comme environnement de développement basé sur les images CUDA et cuDNN fournies par le dépôt nvidia/cuda sur Docker Hub.

  • Il faut décider de l’image à utiliser en tenant compte des versions CUDA et cuDNN nécessaires, du type et de la version de distribution Linux, etc.
  • Version CUDA prise en charge par PyTorch 2.4.0Au moment de la rédaction de cet article, fin août 2024, la dernière version de PyTorch, la version 2.4.0, prend en charge CUDA 12.4. Par conséquent, nous utilisons ici l’image 12.4.1-cudnn-devel-ubuntu22.04. Vous pouvez vérifier la dernière version de PyTorch et la version CUDA prise en charge sur le site web de PyTorch.

Le code source du Dockerfile complet est disponible publiquement dans le dépôt GitHub yunseo-kim/dl-env-docker. Ci-dessous, nous expliquons étape par étape le processus de rédaction de ce Dockerfile.

5-1. Spécification de l’image de base

1
FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04

5-2. Installation des utilitaires de base et des prérequis Python

1
2
3
4
5
6
7
8
9
RUN apt-get update -y && apt-get install -y --no-install-recommends\
    apt-utils \
    ssh \
    curl \
    openssh-server \
    python3 \
    python-is-python3 \
    python3-pip && \
    rm -rf /var/lib/apt/lists/*

5-3. Configuration du fuseau horaire du système (dans cet article, nous procédons avec ‘Asia/Seoul’)

1
2
3
# Set up time zone
ARG TZ="Asia/Seoul"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime

5-4. Configuration du serveur SSH pour l’accès à distance

Pour des raisons de sécurité, configurez de manière à ce que la connexion au compte root ne soit pas possible par mot de passe lors de la connexion SSH à distance.

1
2
# Disable root access via password
RUN echo "PermitRootLogin prohibit-password" >> /etc/ssh/sshd_config

Configurez pour que le service SSH démarre automatiquement au démarrage du conteneur.

1
RUN echo "sudo service ssh start > /dev/null" >> $HOME/.bashrc

Créez un utilisateur non-root nommé ‘remote’ à utiliser lors de la connexion SSH.

1
2
3
4
5
6
7
8
9
10
11
# Create a non-root user and switch to it
ARG USER_NAME="remote"
ARG USER_PASSWORD="000000"
RUN useradd --create-home --password $USER_PASSWORD $USER_NAME
ENV HOME=/home/$USER_NAME
USER $USER_NAME
WORKDIR $HOME
# Re-run ssh when the container restarts.
RUN echo "sudo service ssh start > /dev/null" >> $HOME/.bashrc
# Create a workspace directory to locate jupyter notebooks and .py files
RUN mkdir -p $HOME/workspace

Si aucune option n’est spécifiée lors de la construction de l’image Docker à l’aide de ce Dockerfile, la valeur initiale du mot de passe du compte utilisateur ‘remote’ est 000000. Ceci est très vulnérable en termes de sécurité, donc lors de la construction de l’image Docker, utilisez l’option --build-arg pour spécifier séparément le mot de passe de connexion au compte, ou changez immédiatement les paramètres après avoir exécuté le conteneur pour la première fois. Pour la sécurité, il est souhaitable de désactiver ultérieurement la connexion par mot de passe lors de la connexion SSH et de configurer pour que la connexion ne soit possible que via un fichier de clé séparé, et il serait idéal d’utiliser également une clé matérielle comme Yubikey. La configuration du serveur SSH sera abordée dans une certaine mesure dans la prochaine partie de cette série, et si vous voulez en savoir plus, vous pouvez consulter les documents de la liste suivante.

5-5. Installation de setuptools, pip et enregistrement de la variable d’environnement PATH

1
2
RUN python3 -m pip install -U setuptools pip
ENV PATH="$HOME/.local/bin:$PATH"

5-6. Installation des packages d’apprentissage automatique et d’apprentissage profond à utiliser dans l’environnement de développement

1
2
RUN python3 -m pip install -U jupyterlab numpy scipy pandas matplotlib seaborn[stats] scikit-learn tqdm
RUN python3 -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

Si vous voulez utiliser Cupy, cuDF, cuML et DALI, ajoutez également le contenu suivant au Dockerfile.

1
2
RUN python3 -m pip install -U cupy-cuda12x
RUN python3 -m pip install -U --extra-index-url=https://pypi.nvidia.com cudf-cu12==24.8.* cuml-cu12==24.8.* nvidia-dali-cuda120

5-7. Configuration pour exécuter JupyterLab au démarrage du conteneur

1
2
CMD cd $HOME/workspace && \
    jupyter lab --no-browser --autoreload --ip=0.0.0.0 --notebook-dir="$HOME/workspace"

6. Construction de l’image Docker et exécution du conteneur

6-1. Construction de l’image

Ouvrez un terminal dans le répertoire où se trouve le Dockerfile et exécutez la commande suivante.

1
2
docker build -t dl-env:cuda12.4.1-cudnn9.1.0-ubuntu22.04 -f ./Dockerfile . \
--build-arg USER_PASSWORD=<password>

À la place de <password>, entrez le mot de passe de connexion à utiliser lors de la connexion SSH.

6-2. Exécution d’une charge de travail d’exemple

Une fois la construction terminée, vérifiez si cela fonctionne bien en exécutant un conteneur jetable avec la commande suivante.

1
2
3
docker run -itd --rm --name test-container \
--gpus all -p 88:8888 \
dl-env:cuda12.4.1-cudnn9.1.0-ubuntu22.04

Lorsque vous entrez la commande ci-dessus dans le terminal, elle exécute un conteneur nommé test-container à partir de l’image dl-env:cuda12.4.1-cudnn9.1.0-ubuntu22.04 précédemment construite, puis connecte le port 88 du système hôte au port 8888 de ce conteneur. Si l’image Docker a été correctement construite à l’étape précédente et que le conteneur a démarré sans problème, JupyterLab devrait être en cours d’exécution à l’adresse par défaut http:127.0.0.1:8888 dans le conteneur test-container. Par conséquent, lorsque vous ouvrez un navigateur sur le système hôte où fonctionne le Docker Engine et accédez à http://127.0.0.1:88, il devrait se connecter à l’adresse http://127.0.0.1:8888 à l’intérieur du conteneur et afficher un écran comme ci-dessous.

Capture d'écran de l'interface JupyterLab

6-3. (optionnel) Push vers Docker Hub

Pour pouvoir utiliser l’image de l’environnement de développement créée à travers le processus précédent en la tirant (Pull) à tout moment lorsque nécessaire, il est bon de la pousser (Push) sur Docker Hub.

Pour pousser votre propre image sur Docker Hub, vous avez besoin de votre propre compte Docker, donc si vous n’en avez pas encore, complétez d’abord l’inscription sur https://app.docker.com/signup.

Tout d’abord, connectez-vous à Docker Hub avec la commande suivante.

1
docker login

Maintenant, exécutez une commande au format suivant pour créer un tag d’image.

1
docker tag IMAGE_ID <dockerhub_username>/<repository_name>[:TAG]

Enfin, exécutez la commande suivante pour pousser cette image sur Docker Hub.

1
docker push <dockerhub_username>/<repository_name>[:TAG]

Vous pouvez vérifier sur https://hub.docker.com/ que le Push a bien été effectué comme ci-dessous.
Capture d'écran de Docker Hub

L’image complétée à travers le processus précédent a été rendue publique dans le dépôt public yunseokim/dl-env sur Docker Hub, et peut être utilisée librement par quiconque.

This post is licensed under CC BY-NC 4.0 by the author.

Comments powered by Disqus.