3.1El archivo compose.yml : servicios, puertos, volúmenes
Lo esencial en 30 segundos
- Declarar el estado deseado, no las órdenes : cada servicio tiene su imagen (o build), sus puertos, sus variables, sus volúmenes y su red — Compose lo crea todo desde este archivo versionado.
- Un servicio = imagen + puertos + env + volúmenes : puertos entre comillas ("8080:80"), volúmenes y redes declarados abajo y creados automáticamente, depends_on para el orden de arranque.
- YAML : la indentación es la ley : espacios, nunca tabulaciones, dos espacios por nivel — docker compose config valida y muestra el archivo resuelto antes de cualquier lanzamiento.
Mini-caso hilado — Idir sustituye sus líneas de 200 caracteres
Idir, devops junior en Argel, lanza la maqueta de su equipo con dos líneas docker run de 200 caracteres recopiadas de una chuleta — un puerto olvidado, y la demo falla. Escribe un compose.yml de 25 líneas (web + base, volumen nombrado, depends_on), lo valida con docker compose config, lo commitea : desde ahora, un solo archivo da fe y todo el equipo arranca la misma aplicación. Se acabó la doc « cómo lanzar » recitada de memoria.
Este mismo caso vuelve en el curso, el esquema, el guion y el reto 48h.
1. Declarar en lugar de ordenar : el archivo que da fe
Compose sustituye sus docker run por un archivo versionado : en él se describe el ESTADO DESEADO de la aplicación (qué servicios, qué puertos, qué volúmenes, qué redes) y Compose lo crea todo — redes, volúmenes, contenedores en orden. Se acabaron las líneas de 200 caracteres recopiadas de memoria : el compose.yml se commitea, se revisa como código, y constituye el lanzador oficial de la app. Es el paso del gesto manual a lo declarativo.
Cada servicio (web, bdd, caché…) declara su imagen (o su build local), sus puertos ("8080:80", comillas obligatorias en YAML), su environment, sus volúmenes (pgdata:/var/lib/postgresql/data) y su red. depends_on fija el orden de arranque entre servicios. Los volúmenes y redes se declaran abajo del archivo : Compose los crea automáticamente en el primer up.
2. YAML : la indentación es la ley, config es el juez
Compose habla YAML : espacios y nunca tabulaciones, dos espacios por nivel, « : » seguido de un espacio. Casi todos los errores de Compose vienen de ahí : una indentación rota, puertos sin comillas (¡8080:80 leído como un número sexagesimal!), un « : » sin espacio. Escribir despacio, indentar limpio : eso es el 80 % del trabajo.
El reflejo antes de cada lanzamiento : docker compose config. Este comando valida el archivo y muestra el compose RESUELTO — o el error exacto con su línea. Idir ya nunca lanza un up sobre un archivo no validado : config primero, up después. Un archivo por app, commiteado, validado : reproducible en todas partes.
🔎 Ejemplo concreto — Web + base en 25 líneas, validado antes del lanzamiento
Idir escribe su primer stack web + base, contraseña en variable.
services:
web:
image: nginx:1.27
ports: ["8080:80"]
depends_on: [bdd]
networks: [front]
bdd:
image: postgres:16.4
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes: [pgdata:/var/lib/postgresql/data]
networks: [front]
volumes:
pgdata:
networks:
front:
# Luego : docker compose config (validar), contraseña en .env no commiteado.
Lectura : dos servicios, un volumen persistente, una red, un orden de arranque.
Lección : este archivo commiteado sustituye a toda la doc « cómo lanzar ».
Vocabulario de la sección
- Servicio
- Un contenedor descrito en Compose (web, bdd, caché) : imagen o build, puertos, variables, volúmenes, red.
Ejemplo sencillo: El servicio web de Idir (nginx, puerto 8080 publicado).
Lo que no es: una línea docker run recopiada de memoria.
Reflejo: un rol aplicativo = un servicio declarado.
- depends_on
- El orden de arranque entre servicios : lanza la base antes que la web, sin esperar a que esté lista.
Ejemplo sencillo: web depends_on bdd : la base arranca primero.
Lo que no es: una garantía de que la base está disponible.
Reflejo: ordenar con depends_on, fiabilizar con healthcheck + retry.
- Volumen Compose
- Volumen nombrado declarado abajo del archivo y creado automáticamente : la persistencia de los datos.
Ejemplo sencillo: pgdata montado en /var/lib/postgresql/data.
Lo que no es: datos prisioneros de un contenedor efímero.
Reflejo: todo dato por guardar = volumen nombrado.
- config
- Comando que valida el compose y muestra el archivo resuelto — o el error exacto.
Ejemplo sencillo: Idir pasa config antes de cada up.
Lo que no es: un up a ciegas sobre un YAML roto.
Reflejo: config primero, up después, siempre.
- YAML
- El formato indentado del compose.yml : espacios (nunca tabulaciones), « : » + espacio, puertos entre comillas.
Ejemplo sencillo: "8080:80" entrecomillado, dos espacios por nivel.
Lo que no es: tabulaciones y puertos sin entrecomillar.
Reflejo: espacios, dos por nivel, comillas en los puertos.
En la práctica — Escribir su primer stack
- Cree una carpeta con el compose.yml web + bdd de arriba (contraseña en ${POSTGRES_PASSWORD}, .env local no commiteado).
- Valídelo con docker compose config : lea el archivo resuelto mostrado.
- Corrija hasta cero errores (indentación, comillas de los puertos, « : » + espacio).
- Commitee el archivo : desde ahora es su lanzador oficial, revisado como código.
Guion listo para decir — presentar el compose al equipo (30 s)
« Se acabaron las líneas run de 200 caracteres : un solo compose.yml describe web + base — puertos, volumen, orden de arranque — validado por config y commiteado. Cada uno arranca exactamente la misma aplicación, sin chuleta. »
Para decir en reunión de equipo ; proyectar el config resuelto.
Modelo copiar-pegar — stack web + base válido
services:
web:
image: nginx:1.27
ports:
- "8080:80"
depends_on:
- bdd
networks:
- front
bdd:
image: postgres:16.4
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- front
volumes:
pgdata:
networks:
front:
# .env local (NO commiteado) : POSTGRES_PASSWORD=
Independiente
Un compose.yml validado por config y su demo arranca igual en todas partes.
PYME en Argel
Idir commitea el stack web + base : el equipo arranca la misma maqueta sin chuleta.
Equipo de proyecto
Imponer config en verde + commit del compose antes de toda demo compartida.
Principiante
Esta semana : un stack web + base validado con el botón config, luego commiteado.
✓ Buenas prácticas
- Ponga los puertos entre comillas en YAML ("8080:80"), sistemáticamente.
- Pase docker compose config antes de cada up, y lea lo resuelto.
- Un archivo por app, commiteado y revisado como código.
✗ Errores frecuentes
- Tabulaciones en el YAML : solo espacios, dos por nivel.
- Puertos sin comillas (8080:80 se convierte en un número sexagesimal).
- Creer que depends_on espera a que la base esté lista (solo ordena).
Puntos clave
- Compose DESCRIBE el estado deseado, Docker ejecuta : el archivo versionado sustituye a las líneas run.
- SERVICIO = imagen (o build) + puertos entrecomillados + env + volúmenes + depends_on para el orden.
- YAML : espacios, nunca tabulaciones, « : » + espacio — el 80 % de los errores viene de ahí.
- VOLÚMENES y REDES declarados abajo, creados automáticamente ; config valida antes del up.
Reto 48h — aplique mañana
Sustituya 1 lanzamiento manual por un compose.yml validado (config) y commiteado, con la contraseña en variable.
- Mi app se describe en un archivo versionado.
- Mis puertos están entrecomillados y mi YAML sin tabulaciones.
- Mi config está en verde antes de cada up.
Preguntas frecuentes
¿depends_on espera a que la base esté lista ?
NO : depends_on ORDENA el arranque (la base arranca antes que la web) sin esperar su disponibilidad. Si la web se conecta demasiado pronto, falla : la robustez viene de los healthchecks y los reintentos aplicativos (nivel 4.2). Retenga : ordenar ≠ esperar. Para una maqueta simple, relanzar la web basta ; para un stack real, bucle de reconexión al arrancar en la aplicación.
¿Hay que versionar el compose.yml, y dónde poner los secretos ?
SÍ, siempre : el compose.yml es el lanzador oficial de la app, revisado como código y commiteado. Los SECRETOS nunca figuran en duro : use variables (${POSTGRES_PASSWORD}) alimentadas por un .env local no commiteado (o un secreto gestionado en producción), y versione un .env.example con valores ficticios para documentar las claves esperadas.
¿Qué valida « docker compose config » antes de todo lanzamiento ?