Varios servicios con Docker Compose

Aprende Docker → Lección 8

En cuanto una aplicación tiene más de una pieza —la aplicación y su base de datos, como mínimo— arrancar cada contenedor a mano con sus puertos, sus variables y su red se vuelve insostenible. Compose describe todo eso en un archivo y lo levanta con una orden.

Un archivo con dos servicios

name: mi-proyecto

services:
  web:
    build: ./web
    ports:
      - "8090:80"
    environment:
      ENTORNO: desarrollo
    depends_on:
      - cache

  cache:
    image: alpine:3.22
    command: ["sh","-c","echo 'cache simulada en marcha'; sleep 3600"]

Se levanta y se consulta así:

docker compose up -d
docker compose ps
salidacache  alpine:3.22        Up 2 seconds
web    mi-proyecto-web    Up 2 seconds

Fíjate en la diferencia entre los dos servicios: web usa build y Compose construye su imagen a partir de un Dockerfile; cache usa image y se descarga ya hecha. En un proyecto real lo normal es eso mismo: tu aplicación se construye y la base de datos viene de una imagen oficial.

Lo que Compose hace sin que se lo pidas

Crea una red propia para el proyecto donde cada servicio es alcanzable por su nombre. No hay que averiguar direcciones IP:

docker compose exec web ping -c1 cache
salidaweb alcanza a cache por su nombre

Por eso la cadena de conexión de tu aplicación apunta a cache o a db, el nombre del servicio, y funciona igual en cualquier máquina. Y el puerto publicado sigue llegando desde fuera:

curl http://127.0.0.1:8090/
salida<h1>web</h1>
depends_on no espera a que el servicio esté listo. Solo garantiza el orden de arranque: Compose levanta cache antes que web, pero no espera a que esté aceptando conexiones. Con una base de datos, que tarda segundos en inicializarse, la aplicación arrancará antes y fallará al conectar. La solución es añadir un healthcheck al servicio dependido y usar condition: service_healthy, o que la aplicación reintente la conexión, que suele ser lo más robusto.

Las órdenes del día a día

Qué quieres Orden
Levantar todo en segundo plano docker compose up -d
Reconstruir antes de levantar docker compose up -d --build
Ver el estado docker compose ps
Seguir los registros de todo docker compose logs -f
Los de un servicio docker compose logs -f web
Entrar en un contenedor docker compose exec web sh
Reiniciar uno solo docker compose restart web
Parar y eliminar docker compose down
Eliminar también los volúmenes docker compose down -v
Un archivo base y uno por entorno. Compose admite varios archivos superpuestos: docker compose -f compose.yaml -f compose.qa.yaml up -d parte del primero y le aplica encima lo del segundo. Así el archivo base describe la aplicación y cada entorno solo declara lo que cambia: puertos, variables, réplicas. Es el mismo principio de la lección anterior, aplicado al archivo de orquestación.

Hasta dónde llega Compose

Compose está pensado para una sola máquina. Va perfecto para desarrollo, para integración continua y para servidores modestos donde todo cabe en un host. Lo que no hace es repartir contenedores entre varias máquinas, reemplazarlos sin cortar el servicio ni reponerlos si una máquina cae; para eso están Kubernetes o Docker Swarm.

Dicho eso, conviene no saltar antes de tiempo: muchísimos proyectos viven durante años con Compose en un servidor y un reverse proxy delante, y eso es bastante más fácil de operar que un clúster.