Phase 00 - Lesson 07
Docker para IA
Containers tornam o "funciona na minha máquina" coisa do passado.
Tipo: Build Linguagens: Python Pré-requisitos: Fase 0, Lições 01 e 03 Tempo: ~60 minutos
Objetivos de Aprendizagem
- Construir uma imagem Docker com suporte a GPU usando CUDA, PyTorch e bibliotecas de IA a partir de um Dockerfile
- Montar diretórios do host como volumes para persistir modelos, datasets e código entre reconstruções de containers
- Configurar o NVIDIA Container Toolkit para expor GPUs dentro dos containers
- Orquestrar aplicações de IA multi-serviço (servidor de inferência + banco de dados vetorial) usando Docker Compose
O Problema
Você treinou um modelo no seu laptop com PyTorch 2.3, CUDA 12.4 e Python 3.12. Seu colega tem PyTorch 2.1, CUDA 11.8 e Python 3.10. Seu modelo quebra na máquina dele. Seu Dockerfile funciona em ambas.
Projetos de IA são pesadelos de dependências. Uma stack típica inclui Python, PyTorch, drivers CUDA, cuDNN, bibliotecas C de nível de sistema e pacotes especializados como flash-attn que precisam de versões exatas do compilador. O Docker empacota tudo isso em uma única imagem que roda de forma idêntica em qualquer lugar.
O Conceito
O Docker envolve seu código, runtime, bibliotecas e ferramentas de sistema em uma unidade isolada chamada container. Pense nele como uma máquina virtual leve, exceto que ele compartilha o kernel do sistema operacional do host em vez de rodar o seu próprio, então ele inicia em segundos em vez de minutos.
graph TD
subgraph without["Without Docker"]
A1["Your machine<br/>Python 3.12<br/>CUDA 12.4<br/>PyTorch 2.3"] -->|crashes| X1["???"]
A2["Their machine<br/>Python 3.10<br/>CUDA 11.8<br/>PyTorch 2.1"] -->|crashes| X2["???"]
A3["Server<br/>Python 3.11<br/>CUDA 12.1<br/>PyTorch 2.2"] -->|crashes| X3["???"]
end
subgraph with_docker["With Docker — Same image everywhere"]
B1["Your machine<br/>Python 3.12 | CUDA 12.4<br/>PyTorch 2.3 | Your code"]
B2["Their machine<br/>Python 3.12 | CUDA 12.4<br/>PyTorch 2.3 | Your code"]
B3["Server<br/>Python 3.12 | CUDA 12.4<br/>PyTorch 2.3 | Your code"]
end
Por que projetos de IA precisam de Docker mais do que a maioria
Drivers de GPU são frágeis. Código CUDA 12.4 não roda em CUDA 11.8. O Docker isola o toolkit CUDA dentro do container enquanto compartilha o driver de GPU do host através do NVIDIA Container Toolkit.
Pesos de modelos são grandes. Um modelo de 7B parâmetros tem 14 GB em fp16. Você não quer baixá-lo de novo toda vez que reconstrói. Os volumes do Docker permitem montar um diretório de modelos a partir do host.
Arquiteturas multi-serviço são comuns. Uma aplicação de IA real não é apenas um script Python. É um servidor de inferência, um banco de dados vetorial para RAG, talvez um frontend web. O Docker Compose orquestra todos eles com um único comando.
Vocabulário-chave
| Termo | O que significa |
|---|---|
| Imagem | Um template somente leitura. Sua receita. Construída a partir de um Dockerfile. |
| Container | Uma instância em execução de uma imagem. Sua cozinha. |
| Dockerfile | Instruções para construir uma imagem. Camada por camada. |
| Volume | Armazenamento persistente que sobrevive a reinicializações de containers. |
| docker-compose | Uma ferramenta para definir aplicações multi-container em YAML. |
Padrões comuns de containers em IA
Dev Container
Full toolkit. Editor support. Jupyter. Debugging tools.
Used during development and experimentation.
Training Container
Minimal. Just the training script and dependencies.
Runs on GPU clusters. No editor, no Jupyter.
Inference Container
Optimized for serving. Small image. Fast cold start.
Runs behind a load balancer in production.
Mãos à Obra
Passo 1: Instalar o Docker
# macOS
brew install --cask docker
open /Applications/Docker.app
# Ubuntu
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group change to take effect
Verifique:
docker --version
docker run hello-world
Passo 2: Instalar o NVIDIA Container Toolkit (Linux com GPU NVIDIA)
Isso permite que containers Docker acessem sua GPU. Usuários de macOS e Windows (WSL2) podem pular esta etapa; o Docker Desktop lida com o repasse de GPU de forma diferente nessas plataformas.
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
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/$distribution/libnvidia-container.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
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
Teste o acesso à GPU dentro de um container:
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
Se você vir as informações da sua GPU, o toolkit está funcionando.
Passo 3: Entender as imagens base
Escolher a imagem base certa economiza horas de depuração.
nvidia/cuda:12.4.1-devel-ubuntu22.04
Full CUDA toolkit. Compilers included.
Use for: building packages that need nvcc (flash-attn, bitsandbytes)
Size: ~4 GB
nvidia/cuda:12.4.1-runtime-ubuntu22.04
CUDA runtime only. No compilers.
Use for: running pre-built code
Size: ~1.5 GB
pytorch/pytorch:2.3.1-cuda12.4-cudnn9-runtime
PyTorch pre-installed on top of CUDA.
Use for: skipping the PyTorch install step
Size: ~6 GB
python:3.12-slim
No CUDA. CPU only.
Use for: inference on CPU, lightweight tools
Size: ~150 MB
Passo 4: Escrever um Dockerfile para desenvolvimento de IA
Aqui está o Dockerfile em code/Dockerfile. Percorra-o:
FROM nvidia/cuda:12.4.1-devel-ubuntu22.04
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
RUN apt-get update && apt-get install -y --no-install-recommends \
python3.12 \
python3.12-venv \
python3.12-dev \
python3-pip \
git \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1
RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel
RUN python -m pip install --no-cache-dir \
torch==2.3.1 \
torchvision==0.18.1 \
torchaudio==2.3.1 \
--index-url https://download.pytorch.org/whl/cu124
RUN python -m pip install --no-cache-dir \
numpy \
pandas \
scikit-learn \
matplotlib \
jupyter \
transformers \
datasets \
accelerate \
safetensors
WORKDIR /workspace
VOLUME ["/workspace", "/models"]
EXPOSE 8888
CMD ["python"]
Construa-o:
docker build -t ai-dev -f phases/00-setup-and-tooling/07-docker-for-ai/code/Dockerfile .
Isso demora um pouco na primeira vez (baixando a imagem base CUDA + PyTorch). Builds subsequentes usam camadas em cache.
Execute-o:
docker run --rm -it --gpus all \
-v $(pwd):/workspace \
-v ~/models:/models \
ai-dev python -c "import torch; print(f'PyTorch {torch.__version__}, CUDA: {torch.cuda.is_available()}')"
Execute o Jupyter dentro do container:
docker run --rm -it --gpus all \
-v $(pwd):/workspace \
-v ~/models:/models \
-p 8888:8888 \
ai-dev jupyter notebook --ip=0.0.0.0 --port=8888 --no-browser --allow-root
Passo 5: Montagens de volume para dados e modelos
Montagens de volume são essenciais para o trabalho com IA. Sem elas, seus downloads de modelos de 14 GB desaparecem quando o container para.
# Mount your code
-v $(pwd):/workspace
# Mount a shared models directory
-v ~/models:/models
# Mount datasets
-v ~/datasets:/data
Dentro do seu script de treinamento, carregue a partir do caminho montado:
from transformers import AutoModel
model = AutoModel.from_pretrained("/models/llama-7b")
O modelo fica no sistema de arquivos do seu host. Reconstrua o container quantas vezes quiser sem baixá-lo de novo.
Passo 6: Docker Compose para aplicações de IA multi-serviço
Uma aplicação RAG real precisa de um servidor de inferência e um banco de dados vetorial. O Docker Compose roda ambos com um único comando.
Veja code/docker-compose.yml:
services:
ai-dev:
build:
context: .
dockerfile: Dockerfile
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
volumes:
- ../../../:/workspace
- ~/models:/models
- ~/datasets:/data
ports:
- "8888:8888"
stdin_open: true
tty: true
command: jupyter notebook --ip=0.0.0.0 --port=8888 --no-browser --allow-root
qdrant:
image: qdrant/qdrant:v1.12.5
ports:
- "6333:6333"
- "6334:6334"
volumes:
- qdrant_data:/qdrant/storage
volumes:
qdrant_data:
Inicie tudo:
cd phases/00-setup-and-tooling/07-docker-for-ai/code
docker compose up -d
Agora seu container de desenvolvimento de IA pode alcançar o banco de dados vetorial em http://qdrant:6333 pelo nome do serviço. O Docker Compose cria uma rede compartilhada automaticamente.
Teste a conexão de dentro do container de IA:
from qdrant_client import QdrantClient
client = QdrantClient(host="qdrant", port=6333)
print(client.get_collections())
Pare tudo:
docker compose down
Adicione -v para também deletar o volume do qdrant:
docker compose down -v
Passo 7: Comandos Docker úteis para o trabalho com IA
# List running containers
docker ps
# List all images and their sizes
docker images
# Remove unused images (reclaim disk space)
docker system prune -a
# Check GPU usage inside a running container
docker exec -it <container_id> nvidia-smi
# Copy a file from container to host
docker cp <container_id>:/workspace/results.csv ./results.csv
# View container logs
docker logs -f <container_id>
Use Isso
Agora você tem um ambiente de desenvolvimento de IA reprodutível. Para o restante deste curso:
- Use
docker compose uppara iniciar seu ambiente de desenvolvimento e o banco de dados vetorial juntos - Monte seu código, modelos e dados como volumes para que nada se perca entre reconstruções
- Quando uma lição exigir um novo pacote Python, adicione-o ao Dockerfile e reconstrua
- Compartilhe seu Dockerfile com colegas de equipe. Eles obtêm exatamente o mesmo ambiente.
Sem GPU?
Remova a flag --gpus all e o bloco deploy da NVIDIA. O container ainda funciona para lições baseadas em CPU. O PyTorch detecta a ausência de CUDA e recorre à CPU automaticamente.
Exercícios
- Construa o Dockerfile e execute
python -c "import torch; print(torch.__version__)"dentro do container - Inicie a stack docker-compose e verifique se o Qdrant está acessível a partir do container de IA em
http://qdrant:6333/collections - Adicione
flaskao Dockerfile, reconstrua e execute um servidor de API simples na porta 5000. Mapeie a porta com-p 5000:5000 - Meça o tamanho da imagem com
docker images. Tente trocar a imagem base dedevelpararuntimee compare os tamanhos
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Container | "VM leve" | Um processo isolado usando o kernel do host, com seu próprio sistema de arquivos e rede |
| Camada de imagem | "Passo em cache" | Cada instrução do Dockerfile cria uma camada. Camadas inalteradas ficam em cache, então as reconstruções são rápidas. |
| NVIDIA Container Toolkit | "GPU no Docker" | Um hook de runtime que expõe as GPUs do host aos containers via flag --gpus |
| Montagem de volume | "Pasta compartilhada" | Um diretório no host mapeado para dentro do container. As mudanças persistem após o container parar. |
| Imagem base | "Ponto de partida" | A imagem FROM sobre a qual seu Dockerfile é construído. Determina o que vem pré-instalado. |