Phase 00 - Lesson 07
Docker para IA
Los contenedores hacen que el "funciona en mi máquina" sea cosa del pasado.
Tipo: Build Lenguajes: Python Requisitos previos: Fase 0, Lecciones 01 y 03 Tiempo: ~60 minutos
Objetivos de Aprendizaje
- Construir una imagen Docker con soporte para GPU usando CUDA, PyTorch y bibliotecas de IA a partir de un Dockerfile
- Montar directorios del host como volúmenes para persistir modelos, conjuntos de datos y código entre reconstrucciones de contenedores
- Configurar el NVIDIA Container Toolkit para exponer GPUs dentro de los contenedores
- Orquestar aplicaciones de IA multiservicio (servidor de inferencia + base de datos vectorial) usando Docker Compose
El Problema
Entrenaste un modelo en tu laptop con PyTorch 2.3, CUDA 12.4 y Python 3.12. Tu colega tiene PyTorch 2.1, CUDA 11.8 y Python 3.10. Tu modelo falla en su máquina. Tu Dockerfile funciona en ambas.
Los proyectos de IA son pesadillas de dependencias. Una pila típica incluye Python, PyTorch, drivers CUDA, cuDNN, bibliotecas C a nivel de sistema y paquetes especializados como flash-attn que necesitan versiones exactas del compilador. Docker empaqueta todo esto en una única imagen que se ejecuta de forma idéntica en todas partes.
El Concepto
Docker envuelve tu código, runtime, bibliotecas y herramientas del sistema en una unidad aislada llamada contenedor. Piénsalo como una máquina virtual ligera, excepto que comparte el kernel del sistema operativo del host en lugar de ejecutar el suyo propio, por lo que arranca en segundos en lugar 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 qué los proyectos de IA necesitan Docker más que la mayoría
Los drivers de GPU son frágiles. El código de CUDA 12.4 no se ejecuta en CUDA 11.8. Docker aísla el toolkit CUDA dentro del contenedor mientras comparte el driver de GPU del host a través del NVIDIA Container Toolkit.
Los pesos de los modelos son grandes. Un modelo de 7B parámetros ocupa 14 GB en fp16. No quieres volver a descargarlo cada vez que reconstruyes. Los volúmenes de Docker te permiten montar un directorio de modelos desde el host.
Las arquitecturas multiservicio son comunes. Una aplicación de IA real no es solo un script de Python. Es un servidor de inferencia, una base de datos vectorial para RAG, quizás un frontend web. Docker Compose orquesta todos ellos con un solo comando.
Vocabulario clave
| Término | Qué significa |
|---|---|
| Imagen | Una plantilla de solo lectura. Tu receta. Construida a partir de un Dockerfile. |
| Contenedor | Una instancia en ejecución de una imagen. Tu cocina. |
| Dockerfile | Instrucciones para construir una imagen. Capa por capa. |
| Volumen | Almacenamiento persistente que sobrevive a los reinicios de contenedores. |
| docker-compose | Una herramienta para definir aplicaciones multicontenedor en YAML. |
Patrones comunes de contenedores en 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.
Manos a la Obra
Paso 1: Instalar 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
Verifica:
docker --version
docker run hello-world
Paso 2: Instalar el NVIDIA Container Toolkit (Linux con GPU NVIDIA)
Esto permite que los contenedores Docker accedan a tu GPU. Los usuarios de macOS y Windows (WSL2) pueden omitir este paso; Docker Desktop maneja el paso de GPU de forma diferente en esas 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
Prueba el acceso a la GPU dentro de un contenedor:
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
Si ves la información de tu GPU, el toolkit está funcionando.
Paso 3: Entender las imágenes base
Elegir la imagen base correcta ahorra horas de depuración.
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
Paso 4: Escribir un Dockerfile para desarrollo de IA
Aquí está el Dockerfile en code/Dockerfile. Recórrelo:
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"]
Constrúyelo:
docker build -t ai-dev -f phases/00-setup-and-tooling/07-docker-for-ai/code/Dockerfile .
Esto tarda un rato la primera vez (descargando la imagen base de CUDA + PyTorch). Las construcciones posteriores usan capas en caché.
Ejecútalo:
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()}')"
Ejecuta Jupyter dentro del contenedor:
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
Paso 5: Montajes de volumen para datos y modelos
Los montajes de volumen son fundamentales para el trabajo con IA. Sin ellos, tus descargas de modelos de 14 GB desaparecen cuando el contenedor se detiene.
# Mount your code
-v $(pwd):/workspace
# Mount a shared models directory
-v ~/models:/models
# Mount datasets
-v ~/datasets:/data
Dentro de tu script de entrenamiento, carga desde la ruta montada:
from transformers import AutoModel
model = AutoModel.from_pretrained("/models/llama-7b")
El modelo reside en el sistema de archivos de tu host. Reconstruye el contenedor tantas veces como quieras sin volver a descargarlo.
Paso 6: Docker Compose para aplicaciones de IA multiservicio
Una aplicación RAG real necesita un servidor de inferencia y una base de datos vectorial. Docker Compose ejecuta ambos con un solo comando.
Consulta 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:
Inicia todo:
cd phases/00-setup-and-tooling/07-docker-for-ai/code
docker compose up -d
Ahora tu contenedor de desarrollo de IA puede alcanzar la base de datos vectorial en http://qdrant:6333 por el nombre del servicio. Docker Compose crea una red compartida automáticamente.
Prueba la conexión desde dentro del contenedor de IA:
from qdrant_client import QdrantClient
client = QdrantClient(host="qdrant", port=6333)
print(client.get_collections())
Detén todo:
docker compose down
Agrega -v para también eliminar el volumen de qdrant:
docker compose down -v
Paso 7: Comandos Docker útiles para el trabajo con 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>
Úsalo
Ahora tienes un entorno de desarrollo de IA reproducible. Para el resto de este curso:
- Usa
docker compose uppara iniciar tu entorno de desarrollo y la base de datos vectorial juntos - Monta tu código, modelos y datos como volúmenes para que nada se pierda entre reconstrucciones
- Cuando una lección requiera un nuevo paquete de Python, agrégalo al Dockerfile y reconstruye
- Comparte tu Dockerfile con tus compañeros de equipo. Obtienen exactamente el mismo entorno.
¿Sin GPU?
Elimina la bandera --gpus all y el bloque deploy de NVIDIA. El contenedor sigue funcionando para las lecciones basadas en CPU. PyTorch detecta la ausencia de CUDA y recurre a la CPU automáticamente.
Ejercicios
- Construye el Dockerfile y ejecuta
python -c "import torch; print(torch.__version__)"dentro del contenedor - Inicia la pila de docker-compose y verifica que Qdrant sea accesible desde el contenedor de IA en
http://qdrant:6333/collections - Agrega
flaskal Dockerfile, reconstruye y ejecuta un servidor de API simple en el puerto 5000. Mapea el puerto con-p 5000:5000 - Mide el tamaño de la imagen con
docker images. Intenta cambiar la imagen base dedevelaruntimey compara los tamaños
Términos Clave
| Término | Lo que dice la gente | Lo que realmente significa |
|---|---|---|
| Contenedor | "VM ligera" | Un proceso aislado que usa el kernel del host, con su propio sistema de archivos y red |
| Capa de imagen | "Paso en caché" | Cada instrucción del Dockerfile crea una capa. Las capas sin cambios quedan en caché, por lo que las reconstrucciones son rápidas. |
| NVIDIA Container Toolkit | "GPU en Docker" | Un hook de runtime que expone las GPUs del host a los contenedores mediante la bandera --gpus |
| Montaje de volumen | "Carpeta compartida" | Un directorio del host mapeado dentro del contenedor. Los cambios persisten después de que el contenedor se detiene. |
| Imagen base | "Punto de partida" | La imagen FROM sobre la cual se construye tu Dockerfile. Determina lo que viene preinstalado. |