Un archivo de Compose suele ser la descripción más honesta que tienes de un sistema. Es lo que de verdad arranca en la máquina de desarrollo, en CI y, a veces, en producción. También es un muro de YAML, y quien se incorpora al equipo sigue teniendo que preguntar qué servicio habla con cuál.
Esta guía convierte un archivo de Compose en un diagrama de arquitectura en el que puedes confiar: renderiza el archivo que Compose ejecuta de verdad, asigna cada clave a un elemento del diagrama, añade las llamadas que el archivo no puede expresar y mantén el dibujo sincronizado con el archivo. Al final usamos la herramienta gratuita de Archboard para obtener el primer borrador en segundos.
El ejemplo: un pequeño stack shop
Este es el compose.yaml que vamos a dibujar. Es corto, pero tiene las trampas habituales: un servicio en dos redes, una dependencia que solo existe en un archivo de configuración y una herramienta solo para desarrollo.
name: shop
services:
web:
image: nginx:1.27
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
networks: [frontend]
api:
build: ./api
environment:
DATABASE_URL: postgres://shop:${POSTGRES_PASSWORD}@db:5432/shop
REDIS_URL: redis://cache:6379/0
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks: [frontend, backend]
worker:
build: ./api
command: ["node", "worker.js"]
environment:
DATABASE_URL: postgres://shop:${POSTGRES_PASSWORD}@db:5432/shop
REDIS_URL: redis://cache:6379/0
depends_on:
- db
deploy:
replicas: 2
networks: [backend]
db:
image: postgres:16
environment:
POSTGRES_USER: shop
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shop"]
interval: 5s
networks: [backend]
cache:
image: redis:7
networks: [backend]
adminer:
image: adminer
ports:
- "8081:8080"
profiles: [debug]
networks: [backend]
volumes:
db-data:
networks:
frontend:
backend:
Paso 1: renderiza el archivo que Compose ejecuta de verdad
Los equipos rara vez ejecutan un único archivo tal como está escrito. Un archivo override añade puertos, un archivo .env rellena variables y extends toma campos de otro servicio. Antes de dibujar, pídele el resultado a Compose:
docker compose config > rendered.yaml
docker compose config combina los archivos override, sustituye las variables y resuelve extends, y luego imprime el modelo que Compose va a ejecutar. Dibuja a partir de esa salida, no del archivo que tengas abierto en ese momento.
Una advertencia: la salida contiene los valores reales de tus variables, incluido cualquier secreto que haya en .env. Trata rendered.yaml como el propio archivo .env: no lo incluyas en un commit ni lo compartas.
Paso 2: asigna las claves de Compose a elementos del diagrama
La mayor parte del diagrama sale directamente del archivo:
| Clave de Compose | Elemento del diagrama |
|---|---|
services.<name> |
Una tarjeta por servicio, con el nombre de su clave |
image / build |
En la tarjeta: el tag de la imagen o el contexto de build |
ports (8080:80) |
En la tarjeta y en la conexión que llega desde fuera: :8080 → 80 |
deploy.replicas / scale |
Un número de réplicas en la tarjeta, no cajas extra |
networks |
Un marco por red; cada servicio va en el marco de su primera red |
volumes con nombre |
Un nodo de volumen conectado a los servicios que lo montan |
secrets, configs |
Nodos conectados a los servicios que los usan, solo por nombre |
depends_on |
Orden de arranque, escrito en la tarjeta o como conexión discontinua |
profiles |
Servicios opcionales: déjalos fuera o márcalos como opcionales |
Dos reglas mantienen honesto el dibujo. Un servicio que se une a dos redes, como api, es el puente entre ellas: colócalo en el borde del marco de su primera red y deja que sus conexiones crucen a la otra. Y las réplicas son un número, no una pila de cajas: worker ×2 sigue siendo correcto cuando escalas a cinco.
Paso 3: añade las llamadas que el archivo no muestra
Este es el paso que ninguna herramienta puede hacer por ti. depends_on trata del orden de arranque: Compose arranca db antes que api y, con condition: service_healthy, espera a que pase el healthcheck. No dice nada de quién llama a quién en tiempo de ejecución.
Las llamadas reales se esconden en tres sitios:
- Cadenas de conexión.
DATABASE_URLyREDIS_URLnombran hosts (db,cache) y puertos. Cada una es una conexión del diagrama. - Archivos de configuración montados en los contenedores.
nginx.confcontieneproxy_pass http://api:3000;. Esa es la conexión dewebaapi, y vive fuera del archivo de Compose. - Código. Un servicio puede llamar a otro sin que haya ninguna línea en Compose.
workerusaREDIS_URL, pero no tienedepends_onparacache. Si Redis arranca tarde, el worker falla al arrancar, y el diagrama es el primer lugar donde ese hueco se hace visible.
Una búsqueda rápida encuentra la mayoría:
grep -rnE "://([^/@[:space:]]*@)?(api|web|db|cache)[:/]|proxy_pass" --include="*.conf" --include="*.yaml" --include="*.yml" --include="*.env" .
Después confírmalas con el responsable de cada servicio. Dibuja las llamadas en tiempo de ejecución como conexiones continuas etiquetadas con protocolo y puerto, y deja depends_on como una nota o una conexión discontinua, para que nadie confunda el orden de arranque con tráfico.
Paso 4: decide qué dejar fuera
Un archivo de Compose mezcla el sistema con las herramientas que lo rodean. Normalmente dejas fuera:
- Servicios solo para desarrollo detrás de
profiles, comoadminer, capturadores de correo o proxies de depuración. - Tareas puntuales como migraciones o seeders, salvo que el diagrama trate del despliegue.
- Bind mounts de código fuente y archivos de configuración. Muestra un archivo de configuración solo a través de la dependencia que aporta, como aquí la conexión
proxy_passque sale denginx.conf. - Valores de entorno. Los nombres de variables pueden explicar una conexión; los valores van en tu gestor de secretos, no en un diagrama.
Paso 5: organiza el layout
Coloca el tráfico de izquierda a derecha: el navegador, luego el puerto publicado y después los servicios que hay detrás. Dibuja cada red como un marco, para que una llamada que cruza redes salte a la vista. Agrupa los almacenes de datos y coloca los volúmenes debajo del servicio que los monta. Etiqueta cada conexión con protocolo y puerto, por ejemplo HTTP :3000 o SQL :5432.
Obtén el primer borrador con la herramienta gratuita
No tienes que dibujar las tarjetas a mano. Pega el archivo (o la salida renderizada; la herramienta no lee valores de entorno) en la herramienta gratuita Docker Compose a diagrama. Para verlo no necesitas cuenta. Los servicios se convierten en tarjetas con su imagen, puertos y réplicas, las redes en marcos, los volúmenes con nombre, secrets y configs se conectan a los servicios que los usan, y depends_on se convierte en conexiones entre servicios.
La herramienta solo dibuja lo que dice el archivo. No muestra las llamadas en tiempo de ejecución, no lee valores de entorno ni el contenido de env_file, no sigue include y, en un servicio que usa extends, solo dibuja los campos escritos en ese servicio. Por eso los pasos 1 y 3 siguen importando.
Con una cuenta gratuita abres el resultado en Archboard como un diagrama nuevo; luego añades las conexiones en tiempo de ejecución del paso 3 y quitas el ruido del paso 4. Así queda el stack shop después de esa pasada:
Contenido del diagrama
- Browser
- frontend
- backend
- web
- api
- cache
- db
- worker
- db-data
- HTTP :8080 → 80
- proxy_pass :3000
- SQL :5432
- RESP :6379
- jobs :6379
- /var/lib/postgresql/data
Las tarjetas vienen del pack Docker, el navegador del pack Red, y todo el diagrama cabe en los 15 nodos de diagrama del plan Free. Para otro layout de Docker, con contenedores, un registro y un balanceador de carga, mira el ejemplo Docker Runtime Mesh.
Mantenlo al día
Un diagrama sacado de un archivo de Compose queda obsoleto el día en que alguien añade un servicio. Tres hábitos ayudan:
- Añade una línea a la plantilla de pull request: "¿Añade un servicio, una red, un puerto publicado o una cadena de conexión? Actualiza el diagrama."
- Vuelve a ejecutar
docker compose configen las revisiones y compara la lista de servicios con el diagrama. - Enlaza el diagrama en vivo desde el README en lugar de pegar una captura de pantalla, para que solo haya una copia que actualizar.
Cuando el stack pase a Kubernetes, el mismo método se aplica a los manifiestos; consulta De YAML de Kubernetes a un diagrama de arquitectura.
Preguntas frecuentes
¿depends_on significa que un servicio llama a otro?
No. Controla el orden de arranque y, con condition: service_healthy, también espera a un healthcheck. Las llamadas en tiempo de ejecución salen de las cadenas de conexión, los archivos de configuración y el código.
¿Puedo hacer un diagrama de varios archivos de Compose a la vez?
Primero renderízalos con docker compose config, que combina los archivos override en un solo modelo. La herramienta gratuita lee un archivo cada vez.
¿La herramienta lee mi archivo .env?
No. Las variables no se sustituyen: un tag de imagen o un puerto escrito con una variable, como image: shop-api:${TAG}, se muestra tal cual, y los valores de environment y de env_file no se leen.
¿Debo dibujar una caja por contenedor? Dibuja una tarjeta por servicio y escribe en ella el número de réplicas. Los contenedores individuales van y vienen; el equipo piensa en términos de servicios.
¿Se actualiza el diagrama cuando cambio compose.yaml? No. Es un punto de partida. Mantenlo al día con los hábitos de arriba, o vuelve a dibujarlo con la herramienta y copia tus conexiones en tiempo de ejecución.