Hasta ahora has aprendido a construir imágenes y a lanzar contenedores uno a uno con docker run. Eso funciona bien cuando trabajas con un único contenedor, pero las aplicaciones reales casi nunca son tan simples: una web suele necesitar, además, una base de datos, quizá una caché y otros servicios auxiliares. Coordinar todo eso a mano, con varios comandos docker run larguísimos, se vuelve tedioso y propenso a errores. En esta lección descubrirás Docker Compose, la herramienta que permite definir y ejecutar aplicaciones multi-contenedor de forma declarativa, usando un único archivo de texto. Es una de las herramientas más útiles del ecosistema Docker y la base del Módulo 4.
Objetivos de Aprendizaje
- Entender qué problema resuelve Docker Compose frente a múltiples
docker run. - Conocer qué es el archivo
docker-compose.ymly cómo se estructura. - Distinguir entre
docker compose(v2) ydocker-compose(v1) y saber cuál usar. - Comprender la estructura básica de un archivo Compose.
- Escribir y ejecutar tu primer ejemplo mínimo con Compose.
El Problema: Múltiples docker run
Imagina que quieres levantar una aplicación web sencilla con un servidor Nginx y una base de datos PostgreSQL, ambos conectados en la misma red y con datos persistentes. Sin Compose, tendrías que ejecutar algo parecido a esto:
# 1. Crear una red para que los contenedores se comuniquen
docker network create mi_red
# 2. Crear un volumen para los datos de la base de datos
docker volume create datos_db
# 3. Lanzar la base de datos
docker run -d \
--name db \
--network mi_red \
-e POSTGRES_USER=app_user \
-e POSTGRES_DB=app_db \
-e POSTGRES_PASSWORD=changeme_in_real_env \
-v datos_db:/var/lib/postgresql/data \
postgres:16
# 4. Lanzar el servidor web
docker run -d \
--name web \
--network mi_red \
-p 8080:80 \
nginx:latestAnaliza lo que ocurre aquí:
- Son cuatro comandos distintos que debes recordar y ejecutar en el orden correcto.
- Cada
docker runlleva una larga lista de opciones (--network,-e,-v,-p) fáciles de teclear mal. - Si un compañero quiere replicar tu entorno, tienes que pasarle todos estos comandos y confiar en que los ejecute bien.
- Para apagar todo, tendrías que parar y borrar cada contenedor, la red y, si quieres, el volumen, uno por uno.
Este enfoque es imperativo: describes paso a paso cómo construir el entorno. No escala bien y es difícil de versionar y compartir.
La Solución: Docker Compose
Docker Compose te permite describir toda esa aplicación de forma declarativa en un único archivo llamado docker-compose.yml. En lugar de explicar cómo montar el entorno, declaras cuál es el estado deseado y dejas que Compose se encargue del resto.
Las ventajas frente a múltiples docker run son claras:
| Aspecto | Múltiples docker run |
Docker Compose |
|---|---|---|
| Definición | Comandos sueltos en la terminal | Un único archivo docker-compose.yml |
| Estilo | Imperativo (paso a paso) | Declarativo (estado deseado) |
| Arranque de toda la app | Varios comandos en orden | docker compose up |
| Apagado y limpieza | Parar/borrar cada recurso | docker compose down |
| Versionado en Git | Difícil (comandos sueltos) | Fácil (un archivo de texto) |
| Reproducibilidad | Baja | Alta |
Con Compose, todo el ejemplo anterior se reduce a un archivo y a un solo comando para arrancarlo (docker compose up) y otro para apagarlo (docker compose down).
¿Qué Es el Archivo docker-compose.yml?
El docker-compose.yml es un archivo de texto escrito en formato YAML que describe los componentes de tu aplicación. YAML es un formato legible para humanos basado en pares clave-valor y en la indentación (los espacios al principio de cada línea) para marcar la jerarquía.
Conceptos esenciales que describe el archivo:
- Servicios (
services): los contenedores que forman tu aplicación (la web, la base de datos, etc.). - Redes (
networks): cómo se comunican esos servicios entre sí. - Volúmenes (
volumes): dónde se guardan los datos que deben persistir.
Importante sobre YAML: la indentación debe hacerse siempre con espacios, nunca con tabuladores. Lo habitual son 2 espacios por nivel. Un error de indentación es la causa más común de fallos en un archivo Compose.
docker compose (v2) vs docker-compose (v1)
Aquí hay un detalle que suele confundir a quien empieza. Existen dos formas de invocar Compose:
| Característica | docker-compose (v1) |
docker compose (v2) |
|---|---|---|
| Sintaxis | Comando independiente con guion | Subcomando de docker (sin guion) |
| Lenguaje | Escrito en Python | Integrado en Docker, escrito en Go |
| Estado | Obsoleto (legacy) | Actual y recomendado |
| Instalación | Por separado | Incluido en Docker moderno |
- v1 (
docker-compose): era una herramienta separada que se instalaba aparte. Hoy está obsoleta y ya no recibe nuevas funcionalidades. - v2 (
docker compose): es la versión actual, integrada directamente dentro de la CLI de Docker como un subcomando. Fíjate en que se escribedocker compose(con un espacio, sin guion).
En este curso usaremos siempre la sintaxis moderna docker compose (v2). Si encuentras documentación antigua con docker-compose, ten en cuenta que los comandos son casi idénticos.
Instalación y Verificación
Si tienes una versión reciente de Docker Desktop (Windows o macOS) o de Docker Engine (Linux), Compose v2 ya viene incluido y no tienes que instalar nada. Puedes comprobarlo así:
- Si todo está bien, verás algo como
Docker Compose version v2.x.x. - Si en cambio obtienes un error de "comando no encontrado", necesitas actualizar Docker o instalar el plugin de Compose siguiendo la documentación oficial para tu sistema operativo.
Estructura Básica de un Archivo Compose
Un archivo docker-compose.yml típico tiene esta estructura general:
services: # Bloque principal: define los contenedores
nombre_servicio:
image: ... # Qué imagen usar
ports: ... # Qué puertos exponer
# ... más opciones
networks: # (Opcional) Redes personalizadas
...
volumes: # (Opcional) Volúmenes con nombre
...Desglose de cada bloque de nivel superior:
services: es el bloque obligatorio y más importante. Dentro de él, cada clave es el nombre de un servicio (por ejemplowebodb), y bajo ese nombre se configura el contenedor correspondiente.networks: opcional. Permite definir redes propias para conectar servicios. Si no la incluyes, Compose crea automáticamente una red por defecto donde todos los servicios pueden comunicarse.volumes: opcional. Declara volúmenes con nombre para que los datos persistan entre reinicios.
Nota: en versiones antiguas el archivo empezaba con una línea
version: "3.8". En Compose v2 esa clave ya no es necesaria y se considera obsoleta, por lo que en este curso la omitiremos.
Tu Primer Ejemplo Mínimo
Vamos a crear el "Hola Mundo" de Docker Compose: un único servicio que ejecuta un servidor web Nginx. Es lo más sencillo posible para entender el flujo.
Paso 1: Crear el Archivo
Crea una carpeta vacía para el proyecto y, dentro, un archivo llamado exactamente docker-compose.yml con este contenido:
Explicación línea a línea, pensada para principiantes:
services:: abre el bloque que contiene todos los servicios de la aplicación.web:: el nombre que le damos a nuestro servicio. Podríamos llamarlo como quisiéramos (servidor,front, etc.); aquí elegimosweb.image: nginx:latest: indica que este servicio se basa en la imagen oficialnginx, en su etiquetalatest. Compose la descargará de Docker Hub si no la tienes ya.ports:: abre la lista de puertos que se publican hacia el host.- "8080:80": mapea el puerto 8080 del host (izquierda) al puerto 80 del contenedor (derecha), que es donde Nginx escucha por defecto. Así podrás acceder desde tu navegador enhttp://localhost:8080.
Paso 2: Arrancar la Aplicación
Desde la misma carpeta donde está el docker-compose.yml, ejecuta:
- Compose lee el archivo, descarga la imagen si hace falta, crea una red por defecto y arranca el contenedor.
- Verás los registros (logs) de Nginx en tiempo real en tu terminal.
- Abre
http://localhost:8080en el navegador: deberías ver la página de bienvenida de Nginx.
Para arrancarlo en segundo plano (detached), sin quedar atado a la terminal, añade la opción -d:
Paso 3: Apagar la Aplicación
Cuando termines, detén y elimina todo lo que creó Compose con:
- Este comando para y elimina los contenedores y la red por defecto que se crearon.
- Por defecto no borra los volúmenes con nombre, de modo que tus datos persistentes se conservan.
Con esto has completado el ciclo básico: definir, arrancar y apagar una aplicación con un único archivo y un par de comandos.
Errores Comunes y Consejos
- Usar tabuladores en lugar de espacios: YAML no admite tabuladores para la indentación. Configura tu editor para que inserte espacios y usa 2 por nivel.
- Indentación inconsistente: todos los elementos de un mismo nivel deben tener exactamente la misma sangría. Un espacio de más o de menos rompe el archivo.
- Confundir
docker composecondocker-compose: recuerda que la forma moderna lleva un espacio y no un guion. Si un comando no funciona, comprueba cuál estás usando. - Nombrar mal el archivo: debe llamarse
docker-compose.yml(ocompose.yml) para que Compose lo detecte automáticamente. Si usas otro nombre, tendrás que indicarlo con-f. - Ejecutar el comando desde otra carpeta: Compose busca el archivo en el directorio actual. Asegúrate de estar en la carpeta correcta antes de lanzar
docker compose up. - Consejo: empieza siempre con un ejemplo mínimo que funcione y añade servicios poco a poco. Es más fácil depurar un archivo que crece de forma controlada.
Ejercicios
Ejercicio 1
Comprueba qué versión de Docker Compose tienes instalada y averigua si estás usando la v1 o la v2.
Ejercicio 2
Crea un docker-compose.yml mínimo que levante un servidor Nginx accesible en el puerto 9090 del host.
Ejercicio 3
Explica con tus palabras qué hacen los comandos docker compose up -d y docker compose down, y en qué se diferencian.
Soluciones
Solución al Ejercicio 1
Si el comando funciona y devuelve algo como Docker Compose version v2.x.x, estás usando la v2. La sintaxis con espacio (docker compose) corresponde siempre a la versión moderna. La v1 se invocaría como docker-compose version (con guion) y hoy está obsoleta.
Solución al Ejercicio 2
Archivo docker-compose.yml:
La clave está en el mapeo "9090:80": el puerto 9090 es el del host (lo que escribes en el navegador) y el 80 es el interno del contenedor, donde Nginx escucha. Arráncalo con docker compose up -d y visita http://localhost:9090.
Solución al Ejercicio 3
docker compose up -d: arranca todos los servicios definidos en el archivo en segundo plano (modo detached), creando contenedores, redes y volúmenes según haga falta. La opción-dlibera la terminal para que sigas trabajando.docker compose down: detiene y elimina los contenedores y la red por defecto creados por Compose. Es la operación inversa aup.
La diferencia principal es que up pone en marcha la aplicación y down la apaga y limpia. Además, up -d no bloquea la terminal, mientras que up (sin -d) muestra los logs y queda en primer plano.
Conclusión
En esta lección has entendido qué problema resuelve Docker Compose frente a la coordinación manual de múltiples docker run: pasa de un enfoque imperativo y propenso a errores a uno declarativo, reproducible y fácil de versionar. Has conocido el archivo docker-compose.yml, su estructura básica (services, networks, volumes), la diferencia entre la v1 (docker-compose, obsoleta) y la v2 (docker compose, actual), y has lanzado tu primer ejemplo mínimo con Nginx.
En la siguiente lección, Definiendo Servicios en Docker Compose, profundizaremos en el bloque services y en sus claves más importantes (image, build, ports, volumes, depends_on, networks, restart), para que aprendas a describir contenedores con todo el detalle que necesitan tus aplicaciones reales.
Docker: De Principiante a Avanzado
Módulo 1: Introducción a Docker
- ¿Qué es Docker?
- Instalando Docker
- Arquitectura de Docker
- Comandos Básicos de Docker
- Entendiendo las Imágenes de Docker
- Creando tu Primer Contenedor Docker
Módulo 2: Trabajando con Imágenes Docker
- Docker Hub y Repositorios
- Construyendo Imágenes Docker
- Conceptos Básicos de Dockerfile
- Gestionando Imágenes Docker
- Etiquetado y Publicación de Imágenes
Módulo 3: Contenedores Docker
- Ejecutando Contenedores
- Ciclo de Vida del Contenedor
- Gestionando Contenedores
- Redes en Docker
- Persistencia de Datos con Volúmenes
Módulo 4: Docker Compose
- Introducción a Docker Compose
- Definiendo Servicios en Docker Compose
- Comandos de Docker Compose
- Aplicaciones Multi-Contenedor
- Variables de Entorno en Docker Compose
Módulo 5: Conceptos Avanzados de Docker
- Profundización en Redes Docker
- Opciones de Almacenamiento Docker
- Mejores Prácticas de Seguridad en Docker
- Optimizando Imágenes Docker
- Registro y Monitoreo en Docker
Módulo 6: Docker en Producción
- CI/CD con Docker
- Orquestando Contenedores con Docker Swarm
- Introducción a Kubernetes
- Desplegando Contenedores Docker en Kubernetes
- Escalado y Balanceo de Carga
