5 · docker-compose para serving
Los comandos `docker run` largos con una docena de flags son propensos a errores e irrepetibles. docker-compose escribe toda la configuración multi-contenedor — puertos, variables de entorno, volúmenes — en un solo archivo YAML declarativo que arrancas con un único comando.
docker-compose declara una aplicación multi-contenedor completa — servicios, sus mapeos de puertos, variables de entorno y montajes de volúmenes — en UN solo `docker-compose.yml`, para que `docker compose up` arranque toda la pila de forma reproducible en lugar de un frágil `docker run` tecleado a mano con una docena de flags.
Sin esto:
Sin compose, cada compañero corre el modelo con un comando `docker run` ligeramente distinto, los puertos y variables de entorno se olvidan, y conectar un segundo contenedor (un servidor de tracking, una base de datos) se vuelve un dolor de redes manual.
Una configuración de serving real necesita más que docker run image. Mapeas puertos, fijas variables de entorno (la ruta del modelo, el nivel de log), montas un volumen para que el contenedor pueda leer el archivo del modelo desde el disco, y a menudo corres un segundo contenedor al lado (un servidor de tracking de MLflow, una base de datos, un caché). Expresar todo eso como flags de docker run se vuelve inmanejable rápido — y la siguiente persona tiene que reteclear el mismo conjuro largo, o no funcionará igual.
docker-compose resuelve esto. En lugar de recordar flags, declaras toda la configuración en un archivo docker-compose.yml. Luego docker compose up lee el archivo y arranca todo, y docker compose down lo desmonta todo. La configuración vive en control de versiones, así que es reproducible y revisable.
Las tres cosas que compose configura y que más importan para el serving:
ports—"8000:8000"mapea un puerto del host a un puerto del contenedor, exactamente como-pendocker run. Así es como las peticiones de fuera alcanzan la API del modelo dentro del contenedor.environment— fija variables de entorno dentro del contenedor:MODEL_PATH=/models/model.joblib,LOG_LEVEL=info. Tu app las lee en lugar de codificar valores, así la misma imagen se comporta distinto por entorno (dev vs prod).volumes—"./models:/models"monta una carpeta del host dentro del contenedor. Así es como entra el artefacto del modelo: en lugar de hornear un.joblibgrande dentro de la imagen (lo que forzaría una reconstrucción de imagen cada vez que reentrenas), montas la carpetamodels/, y el contenedor lee el modelo más reciente del disco al arrancar. Cambias el archivo, reinicias el contenedor, modelo nuevo — sin reconstruir.
Qué añade compose sobre docker run. Es declarativo (la configuración es un archivo, no un comando tecleado), reproducible (todos corren la pila idéntica), está bajo control de versiones y — su fortaleza distintiva — orquesta múltiples contenedores en una red compartida con un solo comando. ¿Necesitas correr la API y un servidor de tracking de MLflow? Dos servicios en el mismo YAML, y compose los conecta automáticamente.
Un `docker-compose.yml` que declara un servicio de API de modelo (puertos, variables de entorno, un volumen de modelo montado) más un servidor de tracking de MLflow opcional, todo arrancado con un solo `docker compose up`.
¿Qué añade principalmente docker-compose sobre un comando `docker run` pelado?
- docker-compose declara toda una pila multi-contenedor en un solo `docker-compose.yml`; `docker compose up` la arranca de forma reproducible, `docker compose down` la desmonta.
- Para el serving, los campos clave son `ports` (host:contenedor), `environment` (ruta del modelo, nivel de log) y `volumes` (montar la carpeta del modelo para que reentrenar no necesite reconstruir la imagen).
- La fortaleza distintiva de compose es orquestar múltiples contenedores en una red compartida — la API puede alcanzar un servidor MLflow co-ubicado por su nombre de servicio, sin conexiones manuales.
Las pilas locales de serving de ML (API + servidor de tracking + base de datos) casi siempre se levantan con docker-compose — es la forma estándar de correr y compartir una configuración de ML multi-servicio antes de que vaya a la nube.
Si lo quitas: Harías malabares con varios comandos `docker run` largos a mano, conectarías la red de contenedores manualmente y verías la configuración de cada compañero desviarse — justo la irreproducibilidad que este track combate.