Post

Configuración del entorno de desarrollo de aprendizaje profundo con NVIDIA Container Toolkit y Docker (2) - Configuración del tiempo de ejecución del contenedor para utilizar la GPU, escritura del Dockerfile y construcción de la imagen Docker

Esta serie cubre cómo configurar un entorno de desarrollo de aprendizaje profundo basado en NVIDIA Container Toolkit y Docker localmente, y cómo configurar SSH y Jupyter Lab para utilizarlo como servidor remoto. Esta publicación es la primera de la serie e introduce cómo instalar NVIDIA Container Toolkit.

Resumen

En esta serie, cubriremos el proceso de instalación de NVIDIA Container Toolkit y Docker, y la creación de un entorno de desarrollo de aprendizaje profundo escribiendo un Dockerfile basado en las imágenes CUDA y cuDNN proporcionadas por el repositorio nvidia/cuda en Docker Hub. Para aquellos que lo necesiten, compartimos el Dockerfile y la imagen completados a través de este proceso en GitHub y Docker Hub para que puedan usarlos libremente, y además proporcionamos una guía de configuración de SSH y Jupyter Lab para utilizarlo como servidor remoto.
La serie constará de tres publicaciones, y esta es la segunda de ellas.

Procedemos asumiendo un sistema Linux x86_64 con una tarjeta gráfica NVIDIA compatible con CUDA, y aunque no hemos probado directamente en distribuciones distintas a Ubuntu o Fedora, puede haber algunas diferencias menores en algunos detalles específicos.

Antes de empezar

Este artículo es una continuación de la Parte 1, así que si aún no la has leído, se recomienda leerla primero.

4. Configuración del tiempo de ejecución del contenedor

4-1. Ejecutar el comando nvidia-ctk

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

Este comando modifica el archivo /etc/docker/daemon.json para permitir que Docker utilice el NVIDIA Container Runtime.

4-2. Reiniciar el demonio Docker

Reiniciamos el demonio Docker para aplicar los cambios de configuración.

1
sudo systemctl restart docker

4-3. Verificar que se ha configurado correctamente

Ejecutamos un contenedor CUDA de muestra.

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

Si se muestra una pantalla similar a la siguiente, ha sido exitoso.

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. Escritura del Dockerfile

Escribimos un Dockerfile para usar como entorno de desarrollo basado en las imágenes CUDA y cuDNN proporcionadas por el repositorio nvidia/cuda en Docker Hub.

  • Debemos decidir qué imagen usar considerando las versiones de CUDA y cuDNN necesarias, el tipo y versión de la distribución Linux, etc.
  • Versión de CUDA soportada por PyTorch 2.4.0A partir de finales de agosto de 2024, cuando se escribió este artículo, la versión más reciente de PyTorch, 2.4.0, soporta CUDA 12.4. Por lo tanto, aquí usaremos la imagen 12.4.1-cudnn-devel-ubuntu22.04. Puedes verificar la versión más reciente de PyTorch y la versión de CUDA soportada en la página web de PyTorch.

El código fuente del Dockerfile completado está disponible públicamente en el repositorio de GitHub yunseo-kim/dl-env-docker. A continuación, explicamos paso a paso el proceso de escritura de este Dockerfile.

5-1. Especificar la imagen base

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

5-2. Instalar utilidades básicas y prerrequisitos de 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. Configurar la zona horaria del sistema (en este artículo, procedemos con ‘Asia/Seoul’)

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

5-4. Configurar el servidor SSH para acceso remoto

Configuramos para que no sea posible iniciar sesión en la cuenta root con contraseña durante el acceso remoto SSH por razones de seguridad.

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

Configuramos para que el servicio SSH se inicie automáticamente al iniciar el contenedor.

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

Creamos un usuario no root llamado ‘remote’ para usar al conectarse por 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 no se especifica una opción por separado al construir la imagen Docker usando este Dockerfile, el valor inicial de la contraseña de la cuenta del usuario ‘remote’ es 000000. Esto es muy vulnerable en términos de seguridad, así que asegúrate de especificar una contraseña de inicio de sesión de cuenta por separado usando la opción --build-arg al construir la imagen Docker, o cambiar la configuración inmediatamente después de ejecutar el contenedor por primera vez. Para mayor seguridad, es deseable deshabilitar el inicio de sesión con contraseña al conectarse por SSH y configurarlo posteriormente para que solo sea posible iniciar sesión a través de un archivo de clave separado, e idealmente, utilizar una clave de hardware como Yubikey. La configuración del servidor SSH se tratará hasta cierto punto en la próxima parte de esta serie, y si quieres saber más, puedes consultar los documentos en la siguiente lista.

5-5. Instalar setuptools, pip y registrar la variable de entorno PATH

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

5-6. Instalar paquetes de aprendizaje automático y aprendizaje profundo para usar en el entorno de desarrollo

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 quieres usar Cupy, cuDF, cuML y DALI, agrega también lo siguiente al 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. Configurar la ejecución de JupyterLab al iniciar el contenedor

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

6. Construcción de la imagen Docker y ejecución del contenedor

6-1. Construcción de la imagen

Abre una terminal en el directorio donde se encuentra el Dockerfile y ejecuta el siguiente comando:

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

En el lugar de <password>, ingresa la contraseña de inicio de sesión que usarás para la conexión SSH.

6-2. Ejecutar una carga de trabajo de muestra

Una vez completada la construcción, verifica si funciona correctamente ejecutando un contenedor desechable con el siguiente comando:

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

Al ingresar este comando en la terminal, se ejecutará un contenedor llamado test-container a partir de la imagen dl-env:cuda12.4.1-cudnn9.1.0-ubuntu22.04 que construimos anteriormente, y conectará el puerto 88 del sistema host al puerto 8888 de ese contenedor. Si la imagen Docker se construyó correctamente en el paso anterior y el contenedor se inició sin problemas, JupyterLab debería estar ejecutándose en la dirección predeterminada http:127.0.0.1:8888 dentro del contenedor test-container. Por lo tanto, al abrir un navegador en el sistema host donde se ejecuta Docker Engine y acceder a http://127.0.0.1:88, debería conectarse a la dirección http://127.0.0.1:8888 dentro del contenedor y mostrar una pantalla como la siguiente:

Captura de pantalla de la interfaz de JupyterLab

6-3. (opcional) Subir a Docker Hub

Para poder utilizar la imagen del entorno de desarrollo que creamos a través del proceso anterior en cualquier momento que sea necesario, es bueno subirla a Docker Hub.

Para subir tu propia imagen a Docker Hub, necesitas tu propia cuenta de Docker, así que si aún no tienes una, primero completa el registro en https://app.docker.com/signup.

Primero, inicia sesión en Docker Hub con el siguiente comando:

1
docker login

Ahora, ejecuta un comando con el siguiente formato para crear una etiqueta de imagen:

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

Finalmente, ejecuta el siguiente comando para subir la imagen a Docker Hub:

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

Puedes confirmar que se ha subido correctamente en https://hub.docker.com/ como se muestra a continuación:
Captura de pantalla de Docker Hub

La imagen completada a través del proceso anterior está disponible públicamente en el repositorio público yunseokim/dl-env en Docker Hub, y cualquiera puede usarla libremente.

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

Comments powered by Disqus.