Guía de Despliegue: CI/CD y Docker para Sistemas Estadísticos

Esta guía cubre el ciclo completo de despliegue: desde el primer commit hasta la producción, integrando GitHub Actions, Docker, MLflow y buenas prácticas de MLOps.


1. ¿Por qué CI/CD y Docker son indispensables en estadística?

La combinación de CI/CD (Integración Continua / Despliegue Continuo) y Docker no es un lujo: es un requisito para sistemas estadísticos profesionales.

1.1 CI/CD: automatización de la confianza

En un proyecto estadístico, los cambios frecuentes en datos, modelos y código hacen que el despliegue manual sea inviable y peligroso. CI/CD automatiza:

  • Reproducibilidad: cada ejecución del pipeline captura el entorno exacto (dependencias, versión de datos, hash de Git). Si un modelo funcionaba hace tres meses, se puede reconstruir exactamente.
  • Calidad continua: antes de cualquier despliegue se ejecutan pruebas unitarias, de integración, validación de datos y gates de calidad (R-hat, ESS, AUC). Si algo falla, el pipeline se detiene.
  • Detección temprana de errores: un error en una transformación de datos se detecta minutos después del commit, no semanas después en producción.
  • Auditoría y trazabilidad: cada despliegue queda asociado a un run_id de MLflow, un hash de Git y un hash DVC del dataset. Esto permite responder preguntas regulatorias: "¿con qué datos se entrenó el modelo en producción el 15 de marzo?".

Truco de experto: guarda el hash de Git y el hash de DVC como parámetros en MLflow. Así, desde el modelo registrado puedes recuperar exactamente el código y los datos que lo generaron.

1.2 Docker: el entorno como código

Docker permite empaquetar la aplicación con todo su entorno: sistema operativo, lenguajes, librerías y variables de entorno. Esto elimina el clásico "en mi máquina funciona". Un contenedor garantiza que el mismo código se ejecute idénticamente en desarrollo, staging, producción o en la máquina de cualquier colaborador.

Por qué Docker es crítico para estadística:

  • Dependencias conflictivas: un proyecto puede necesitar Python 3.11 y otro Python 3.8; Docker los aísla.
  • Reproducibilidad de análisis pasados: guardando la imagen Docker junto con el código, puedes recrear el entorno exacto de un análisis de hace un año.
  • Despliegue en cualquier orquestador (Kubernetes, ECS, Nomad) sin cambios en la aplicación.

2. Principios clave del pipeline

  • Falla rápido: cada paso falla inmediatamente si hay errores de calidad, pruebas o vulnerabilidades. No se continúa al siguiente paso.
  • Trazabilidad: cada despliegue a producción tiene un run_id de MLflow, un hash de Git y un hash DVC del dataset. Todos se registran en logs y en el model registry.
  • Separación de concerns: los workers de entrenamiento (Celery) son independientes de los workers de la API (Uvicorn). Cada uno se escala por separado según la carga.
  • Staging obligatorio: ningún cambio va directo a producción. Siempre pasa por staging, donde se ejecutan pruebas de humo y validación de latencia.
  • Promoción manual o con gate automático: la promoción a producción puede ser manual (para modelos críticos) o automática (si el gate de calidad pasa). Ver MLflow y Gestión de Modelos.

3. Flujo de trabajo completo (paso a paso)

3.1 Diagrama general

3.2 Explicación de cada etapa

  1. Creación de rama feature: se ramifica desde main con nombre feature/descripcion. Los experimentos se hacen aquí sin afectar la rama principal.
  2. Desarrollo y commits: se escribe código y se suben los cambios. Cada commit debería pasar las pruebas localmente antes de hacer push.
  3. Pull Request: se abre un PR contra main. Automáticamente, GitHub Actions ejecuta el pipeline de CI (linting, pruebas unitarias, integración).
  4. Revisión de código: al menos un revisor aprueba el PR. La revisión debe verificar no solo el código, sino también decisiones estadísticas (elección de priors, validaciones, etc.).
  5. Merge a main: una vez aprobado, se fusiona. Este evento dispara el pipeline de CD.
  6. Build de Docker + Trivy: se construye la imagen y se verifica que no tenga vulnerabilidades críticas.
  7. Despliegue a staging: se actualiza el entorno de staging con la nueva imagen.
  8. Pruebas de humo: se ejecutan pruebas rápidas: health endpoint, predicción sobre registros de ejemplo, latencia < 200 ms.
  9. Gate de calidad: automático (métricas de modelo) o manual (aprobación en GitHub).
  10. Despliegue a producción: la imagen se despliega en el entorno de producción.

4. Secuencia detallada del pipeline

text

Cada paso está en un job separado dentro de GitHub Actions para que se puedan ejecutar en paralelo cuando sea posible.


5. Pipeline completo con GitHub Actions

El siguiente workflow se activa con cada push a main y también puede ejecutarse manualmente (workflow_dispatch).

yaml

Truco de experto: usa if: github.event_name == 'workflow_dispatch' para que el despliegue a producción sea siempre manual. Si prefieres automático, cambia la condición a if: always() y añade un gate de calidad dentro del job.


6. Docker: buenas prácticas profundizadas

6.1 Dockerfile para la API (Python + FastAPI)

dockerfile

Buenas prácticas aplicadas en este Dockerfile:

  • Imagen base -slim: mucho más pequeña que la completa, reduce la superficie de ataque.
  • Orden de capas: dependencias al principio, código al final. Cuando cambias solo el código, Docker reutiliza la capa de dependencias en caché, acelerando el build.
  • Usuario no root: si un atacante compromete el contenedor, no tiene privilegios de root.
  • Healthcheck: permite a Kubernetes o ECS reiniciar automáticamente el contenedor si falla.

6.2 Dockerfile para dashboard (Next.js)

dockerfile

Truco: el patrón multi-stage build (etapas builder y runner) reduce drásticamente el tamaño de la imagen final: el código fuente y las dependencias de desarrollo no se incluyen en la imagen de producción.

6.3 Docker Compose completo

yaml

Error común: usar localhost:8000 en NEXT_PUBLIC_STATS_API_URL dentro del contenedor del dashboard. Esto falla porque cada contenedor tiene su propia red virtual. La solución es usar el nombre del servicio (api).

6.4 Tabla de buenas prácticas Docker

PrácticaJustificación
Imágenes base ligeras (-slim, -alpine)Menor tamaño y menor superficie de ataque.
Capas ordenadas (dependencias antes que código)Maximiza la caché de Docker; rebuilds más rápidos.
Usuario no root (RUN useradd, USER)Reduce el riesgo si el contenedor es comprometido.
Secretos en variables de entorno, nunca en la imagenEvitar leakage de credenciales en el registro.
HEALTHCHECK definidoEl orquestador detecta y reinicia contenedores caídos.
Logs a stdout/stderrLos orquestadores (Kubernetes, ECS) los capturan automáticamente.
Etiquetado semántico + commit SHATrazabilidad: saber exactamente qué código está en producción.

7. Integración de GitHub y Docker (CI/CD completo)

7.1 Diagrama de flujo integrado

7.2 Workflow de construcción y publicación de imágenes

Este workflow es independiente del entrenamiento y se activa al crear un tag semántico (v*).

yaml

Truco: usa dos tags: latest (para desarrollo) y la versión semántica (para producción). Así puedes hacer rollback fácilmente apuntando al tag anterior.


8. Gate de calidad automático

El siguiente script se ejecuta después del entrenamiento y decide si promueve el modelo a staging.

python

En el workflow de GitHub Actions, después del entrenamiento:

yaml

9. Pruebas de humo en staging

Guarda esto en tests/smoke/test_smoke_staging.py.

python

Ejecución en el pipeline:

yaml

10. Checklist de despliegue

  • El pipeline de CI/CD pasa todas las pruebas (unitarias, integración, contrato de datos).
  • La imagen Docker se construye sin errores y tiene menos de 500 MB.
  • Trivy no encuentra vulnerabilidades CRITICAL en la imagen.
  • La imagen está etiquetada con el commit SHA y con la versión semántica.
  • El entorno de staging se actualiza correctamente.
  • Las pruebas de humo pasan (health, predict, latencia).
  • El gate de calidad promueve el modelo a staging.
  • La aprobación manual (si aplica) ha sido concedida.
  • El despliegue a producción no falla y el modelo responde en producción.
  • Los logs de auditoría contienen el run_id de MLflow y el hash de Git.

Documentos relacionados


Referencias y recursos externos