Introduccion y casos de uso
Docker Compose orquesta varios contenedores con un unico fichero YAML. En lugar de lanzar docker run a mano (puertos, redes, volumenes, variables), defines el stack una vez y lo levantas con docker compose up.
Este manual usa Compose V2: el comando es docker compose (plugin del CLI de Docker), no el binario legacy docker-compose.
Capitulos
- Introduccion y casos de uso
- Servicios, redes y volumenes
- Variables de entorno
- Healthchecks y dependencias
- Perfiles y overrides
- Stacks de desarrollo
- Buenas practicas
Que problema resuelve
Sin Compose, un entorno tipico (API + Postgres + Redis) exige varios docker run, nombres de red inventados y flags faciles de olvidar:
docker network create appnet
docker run -d --name db --network appnet -e POSTGRES_PASSWORD=secret postgres:16
docker run -d --name redis --network appnet redis:7
docker run -d --name api --network appnet -p 3000:3000 \
-e DATABASE_URL=postgres://postgres:secret@db:5432/app \
-e REDIS_URL=redis://redis:6379 \
mi-api:devCon Compose:
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
redis:
image: redis:7
api:
image: mi-api:dev
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://postgres:secret@db:5432/app
REDIS_URL: redis://redis:6379
depends_on:
- db
- redisdocker compose up -dCompose crea el project name (por defecto el nombre del directorio), una red bridge compartida y resuelve DNS entre servicios por el nombre del servicio (db, redis, api).
Compose V2 vs docker-compose V1
| Aspecto | Compose V2 | docker-compose V1 |
|---|---|---|
| Comando | docker compose | docker-compose |
| Instalacion | Plugin del Docker CLI | Binario Python separado |
| Estado | Actual y soportado | Obsoleto |
| Fichero | compose.yaml o docker-compose.yml | Igual |
Clave version: | Ignorada / innecesaria | Obligatoria en versiones antiguas |
Comprueba la instalacion:
docker compose versionSi falla, instala el plugin segun tu distro o actualiza Docker Desktop. En este manual todos los ejemplos usan docker compose.
Anatomia de un proyecto
Layout tipico:
mi-proyecto/
|-- compose.yaml # stack principal (o docker-compose.yml)
|-- .env # variables para interpolacion (no secretos de prod)
|-- .env.example # plantilla versionada sin secretos
|-- Dockerfile # build de la app
`-- app/ # codigo fuenteNombres de fichero reconocidos (en orden de preferencia Compose): compose.yaml, compose.yml, docker-compose.yaml, docker-compose.yml.
Primer stack en 2 minutos
Crea un directorio y un compose.yaml:
mkdir compose-demo && cd compose-demoservices:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"Levanta, prueba y limpia:
docker compose up -d
curl -I http://127.0.0.1:8080
docker compose ps
docker compose logs web
docker compose downup -d arranca en segundo plano. down detiene y elimina contenedores y la red del proyecto; los volumenes nombrados solo se borran con down -v.
Modelo mental
compose.yaml
|
v
docker compose up
|
+--> crea red <proyecto>_default
+--> crea volumenes declarados
+--> build / pull imagenes
+--> arranca contenedores (1 por servicio, salvo scale)
+--> DNS interno: nombre-servicio -> IP del contenedorEl project name agrupa recursos. Por defecto es el nombre del directorio; puedes fijarlo:
docker compose -p tienda up -dLos recursos quedan etiquetados (com.docker.compose.project=tienda) y no chocan con otro stack en el mismo host.
Casos de uso reales
1. Desarrollo local de una app con dependencias
API + base de datos + cola + mailcatcher. El equipo comparte el mismo compose.yaml y evita "en mi maquina funciona" por versiones distintas de Postgres o Redis.
2. Smoke tests y CI
En un job de GitHub Actions levantas el stack, esperas healthchecks y lanzas tests de integracion. Al terminar, docker compose down -v deja el runner limpio.
3. Demos y workshops
Un unico compose up muestra el producto completo (frontend, API, DB) sin instalar runtimes en el host.
4. Sidecars de observabilidad en local
Anadir Prometheus, Grafana o Mailhog solo en desarrollo con perfiles, sin ensuciar el stack minimo.
Cuando NO es la herramienta adecuada
| Escenario | Mejor opcion |
|---|---|
| Un solo contenedor puntual | docker run |
| Orquestacion multi-nodo, rolling updates, autoscaling | Kubernetes / Nomad |
| Produccion con HA serio | Orquestador + IaC; Compose solo en un nodo (Compose Swarm esta deprecado en la practica) |
| Secrets rotativos empresariales | Vault / secrets del orquestador, no .env en disco |
Compose brilla en un host: laptop, CI, VPS pequena. No sustituye un cluster.
Comandos del dia a dia
docker compose up -d # arrancar
docker compose up -d --build # rebuild imagenes locales
docker compose ps # estado
docker compose logs -f api # logs de un servicio
docker compose exec api sh # shell en contenedor en marcha
docker compose run --rm api npm test # one-shot sin dejar contenedor
docker compose stop # parar sin borrar
docker compose start # reanudar
docker compose restart api
docker compose down # parar y borrar contenedores + red
docker compose down -v # ademas borra volumenes nombrados
docker compose config # renderiza YAML final (interpolacion resuelta)
docker compose config --quiet # valida sin imprimir (exit != 0 si hay error)docker compose config es tu aliado: muestra el fichero efectivo tras merges de overrides y sustitucion de variables. Si algo "no cuadra", miralo ahi primero.
Conceptos clave
| Concepto | Significado |
|---|---|
| Servicio | Unidad logica en el YAML; suele mapear a un contenedor |
| Proyecto | Namespace de recursos (redes, volumenes, contenedores) |
| Red | Bridge donde los servicios se descubren por nombre |
| Volumen | Persistencia fuera del ciclo de vida del contenedor |
| Build | Contexto Dockerfile asociado a un servicio |
| Override | Ficheros extra que Compose fusiona (compose.override.yaml) |
Errores habituales
- Usar
docker-compose(V1) en docs nuevas y chocar con entornos que solo tienen el plugin V2. - Dejar
version: "3.9"pensando que activa features; en Compose V2 se ignora. Mejor omitirla. - Confundir el nombre del servicio (
db) con el hostname del contenedor generado (proyecto-db-1): dentro de la red Compose, el DNS correcto es el nombre del servicio. - Ejecutar
composedesde otro directorio sin-fy creer que "no encuentra" el fichero. down -ven un entorno con datos de desarrollo que queriamos conservar.
Buenas practicas
- Un
compose.yamlversionado en git; secretos fuera (.enven.gitignore, ver capitulo 3). - Nombres de servicio cortos y estables (
api,db,redis): son hostnames. - Documenta en el README del repo:
docker compose up -dy puertos expuestos. - Prefiere imagenes con tag fijo (
postgres:16.4) frente a:latesten stacks compartidos. - Valida siempre con
docker compose configantes de depurar "comportamientos raros".
Ejercicios
- Crea un
compose.yamlcon Nginx en el puerto 8080, levantalo y responde con el status HTTP decurl -I. - Cambia el project name con
-p demoy comprueba condocker ps --format '{{.Names}}'que los contenedores llevan el prefijodemo-. - Ejecuta
docker compose configy localiza la red por defecto que Compose inyecta. - Para el stack con
stop, vuelve a arrancarlo constarty compara condown+up(estado de contenedores nuevos vs reutilizados).
Siguiente paso
En Servicios, redes y volumenes defines builds, bind mounts, volumenes nombrados y redes custom para que los servicios hablen entre si de forma predecible.
