Post

Construindo um ambiente de desenvolvimento de Deep Learning com NVIDIA Container Toolkit e Docker (2) - Configuração do runtime do contêiner para utilização da GPU, escrita do Dockerfile e construção da imagem Docker

Esta série aborda como configurar um ambiente de desenvolvimento de Deep Learning baseado em NVIDIA Container Toolkit e Docker localmente, e como configurar SSH e Jupyter Lab para utilizá-lo como um servidor remoto. Este post é o segundo da série e apresenta como configurar o runtime do contêiner para utilização da GPU, escrever o Dockerfile e construir a imagem Docker.

Visão geral

Nesta série, abordamos o processo de instalação do NVIDIA Container Toolkit e Docker, e a construção de um ambiente de desenvolvimento de Deep Learning escrevendo um Dockerfile baseado nas imagens CUDA e cuDNN fornecidas pelo repositório nvidia/cuda no Docker Hub. Para aqueles que precisam, compartilhamos o Dockerfile e a imagem concluídos através deste processo no GitHub e Docker Hub para uso livre, e fornecemos adicionalmente um guia de configuração de SSH e Jupyter Lab para utilização como servidor remoto.
A série consistirá em 3 posts, e este é o segundo post da série.

Prosseguiremos assumindo um sistema Linux x86_64 com uma placa gráfica NVIDIA que suporta CUDA, e embora não tenhamos testado diretamente em distribuições além do Ubuntu ou Fedora, pode haver algumas pequenas diferenças em alguns detalhes específicos.

Antes de começar

Este post é uma continuação da Parte 1, então se você ainda não leu, recomendo que leia o post anterior primeiro.

4. Configuração do runtime do contêiner

4-1. Executar o comando nvidia-ctk

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

Este comando modifica o arquivo /etc/docker/daemon.json para permitir que o Docker utilize o NVIDIA Container Runtime.

4-2. Reiniciar o daemon do Docker

Reinicie o daemon do Docker para aplicar as configurações alteradas.

1
sudo systemctl restart docker

4-3. Verificar se foi configurado corretamente

Execute um contêiner CUDA de exemplo.

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

Se uma tela semelhante à seguinte for exibida, foi bem-sucedido.

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. Escrita do Dockerfile

Escreveremos um Dockerfile para usar como ambiente de desenvolvimento baseado nas imagens CUDA e cuDNN fornecidas pelo repositório nvidia/cuda no Docker Hub.

  • Você deve decidir qual imagem usar considerando as versões necessárias de CUDA e cuDNN, o tipo e versão da distribuição Linux, etc.
  • CUDA version supported by PyTorch 2.4.0No momento da escrita deste post, no final de agosto de 2024, a versão mais recente do PyTorch, 2.4.0, suporta CUDA 12.4. Portanto, usaremos a imagem 12.4.1-cudnn-devel-ubuntu22.04 aqui. Você pode verificar a versão mais recente do PyTorch e as versões CUDA suportadas na página inicial do PyTorch.

O código-fonte do Dockerfile concluído está disponível publicamente no repositório GitHub yunseo-kim/dl-env-docker. Abaixo, explicamos o processo de escrita deste Dockerfile passo a passo.

5-1. Especificar a imagem base

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

5-2. Instalar utilitários básicos e pré-requisitos do 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 o fuso horário do sistema (neste post, usaremos ‘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 o servidor SSH para acesso remoto

Configure para que o login na conta root não seja possível com senha durante o acesso SSH remoto por motivos de segurança.

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

Configure para que o serviço SSH inicie automaticamente quando o contêiner for iniciado.

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

Crie um usuário não-root chamado ‘remote’ para usar ao acessar via 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

Se você não especificar opções separadas ao construir a imagem Docker usando este Dockerfile, o valor inicial da senha da conta do usuário ‘remote’ será 000000. Isso é extremamente vulnerável em termos de segurança, então use a opção --build-arg ao construir a imagem Docker para especificar uma senha de login de conta separadamente, ou altere as configurações imediatamente após executar o contêiner pela primeira vez. Para segurança, é desejável desativar o login por senha ao acessar via SSH e configurar posteriormente para permitir o login apenas através de um arquivo de chave separado, e seria ideal usar uma chave de hardware como o Yubikey. A configuração do servidor SSH será abordada até certo ponto na próxima parte desta série, e se você quiser saber mais detalhes, pode consultar os documentos na seguinte lista:

5-5. Instalar setuptools, pip e registrar a variável de ambiente PATH

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

5-6. Instalar pacotes de machine learning e deep learning para usar no ambiente de desenvolvimento

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

Se você quiser usar Cupy, cuDF, cuML e DALI, adicione o seguinte conteúdo ao 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 para executar o JupyterLab ao iniciar o contêiner

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

6. Construir a imagem Docker e executar o contêiner

6-1. Construir a imagem

Abra um terminal no diretório onde o Dockerfile está localizado e execute o seguinte comando:

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

No lugar de <password>, insira a senha de login que você usará ao acessar via SSH.

6-2. Executar uma carga de trabalho de exemplo

Após concluir a construção, execute o seguinte comando para iniciar um contêiner descartável e verificar se está funcionando corretamente:

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

Quando você inserir o comando acima no terminal, ele executará um contêiner chamado test-container a partir da imagem dl-env:cuda12.4.1-cudnn9.1.0-ubuntu22.04 que acabamos de construir e conectará a porta 88 do sistema host à porta 8888 desse contêiner. Se a imagem Docker foi construída corretamente na etapa anterior e o contêiner foi iniciado sem problemas, o JupyterLab deve estar em execução no endereço padrão http:127.0.0.1:8888 dentro do contêiner test-container. Portanto, ao abrir um navegador no sistema host onde o Docker Engine está em execução e acessar http://127.0.0.1:88, você deve ser conectado ao endereço http://127.0.0.1:8888 dentro do contêiner e ver uma tela como a seguinte:

JupyterLab Interface Screenshot

6-3. (opcional) Fazer Push para o Docker Hub

Para poder utilizar a imagem do ambiente de desenvolvimento que criamos através do processo anterior sempre que necessário, é bom fazer o Push da imagem construída para o Docker Hub.

Para fazer o Push de sua própria imagem para o Docker Hub, você precisa de uma conta Docker, então se ainda não tiver uma, primeiro complete o registro em https://app.docker.com/signup.

Primeiro, faça login no Docker Hub com o seguinte comando:

1
docker login

Agora, execute um comando no seguinte formato para criar uma tag de imagem:

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

Por fim, execute o seguinte comando para fazer o Push da imagem para o Docker Hub:

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

Você pode confirmar que o Push foi bem-sucedido em https://hub.docker.com/ como mostrado abaixo:
Docker Hub Screenshot

A imagem concluída através do processo anterior está disponível publicamente no repositório público yunseokim/dl-env no Docker Hub e pode ser usada livremente por qualquer pessoa.

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

Comments powered by Disqus.