Contenido
Tutorial de Docker Compose: administra varios contenedores con un solo archivo
Una aplicación real suele tener más de un contenedor: un sitio web, una base de datos, una caché… Para cada uno tienes que recordar una larga lista de parámetros de docker run, crear primero la red y el Volume, y tener en cuenta el orden de inicio.
Docker Compose te permite escribir toda esta configuración en un archivo YAML y luego iniciarlo todo con un solo comando:
docker compose up -d
Instalación y versión
- Docker Desktop (Windows, macOS) ya incluye Compose.
- Linux: sigue los pasos de Instalar Docker e instala
docker-compose-plugin.
$ docker compose version
Docker Compose version v5.6.0
El programa independiente de la versión anterior se llamaba
docker-compose(con guion, v1) y ya no tiene mantenimiento; ahora usadocker compose(con espacio). El número de versión de Compose saltó directamente de la v2 a la v5, pero su uso no ha cambiado. Los tutoriales antiguos de internet mezclan ambos; los comandos y parámetros son prácticamente iguales.
Proyecto de ejemplo: sitio web + base de datos + interfaz de administración
Crea la carpeta compose-demo con esta estructura:
compose-demo/
├── compose.yaml
└── site/
└── index.html
Pon una página web sencilla (con el contenido que quieras) en site/index.html. Este es el archivo compose.yaml:
services:
web:
image: nginx:1.30-alpine
ports:
- "8080:80"
volumes:
- ./site:/usr/share/nginx/html:ro
db:
image: postgres:18
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql
adminer:
image: adminer
ports:
- "8081:8080"
depends_on:
- db
volumes:
pgdata:
Los tres servicios:
| Servicio | Función |
|---|---|
web | nginx, usa la carpeta ./site como sitio web, en el puerto 8080 del host |
db | PostgreSQL 18; los datos se guardan en un Volume llamado pgdata (ten en cuenta que la versión 18 monta /var/lib/postgresql; consulta Volume) |
adminer | Herramienta web de administración de bases de datos, en el puerto 8081 del host |
Para escribir la misma configuración con docker run, primero tendrías que ejecutar docker network create y docker volume create, y después ejecutar tres comandos docker run muy largos.
Inicio: docker compose up
Ejecuta este comando dentro de la carpeta compose-demo:
$ docker compose up -d
[+] up 34/34
✔ Image nginx:1.30-alpine Pulled 7.8s
✔ Image adminer Pulled 8.7s
✔ Network compose-demo_default Created 0.1s
✔ Volume compose-demo_pgdata Created 0.0s
✔ Container compose-demo-web-1 Started 1.7s
✔ Container compose-demo-db-1 Started 0.8s
✔ Container compose-demo-adminer-1 Started 1.0s
Un solo comando lo ha hecho todo: descargar las imágenes (aparece Pulled solo la primera vez), crear la red y el Volume, e iniciar los tres contenedores.
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
compose-demo-adminer-1 adminer "entrypoint.sh docke…" adminer 10 seconds ago Up 9 seconds 0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp
compose-demo-db-1 postgres:18 "docker-entrypoint.s…" db 10 seconds ago Up 10 seconds 5432/tcp
compose-demo-web-1 nginx:1.30-alpine "/docker-entrypoint.…" web 10 seconds ago Up 9 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
$ docker network ls --filter name=compose-demo
NETWORK ID NAME DRIVER SCOPE
a722da926fbd compose-demo_default bridge local
$ docker volume ls --filter name=compose-demo
DRIVER VOLUME NAME
local compose-demo_pgdata
- El nombre del contenedor sigue el patrón
nombre-del-proyecto-nombre-del-servicio-número. De forma predeterminada, el nombre del proyecto es el de la carpeta (compose-demo), así que los proyectos de carpetas distintas no interfieren entre sí. - Compose ha creado automáticamente la red
compose-demo_default. Los tres servicios están en ella y pueden conectarse entre sí usando sus nombres de servicio. - El nombre real del Volume
pgdataescompose-demo_pgdata. dbno tieneportsconfigurado, así que el campo PORTS solo muestra5432/tcpy no se puede acceder desde el exterior.
Abre http://localhost:8080:

Gestionar la base de datos con Adminer
Al abrir http://localhost:8081, aparece la pantalla de inicio de sesión de Adminer. Ten en cuenta que System está configurado de forma predeterminada como MySQL:

Inicia sesión con la siguiente configuración:
| Campo | Valor |
|---|---|
| System | PostgreSQL (debes cambiarlo; de lo contrario, intentará conectarse como MySQL y fallará) |
| Server | db (nombre del servicio, resuelto a través de la red de Compose) |
| Username | postgres |
| Password | example (POSTGRES_PASSWORD en compose.yaml) |

Cuando hayas iniciado sesión, la pantalla mostrará la versión de PostgreSQL y la lista de bases de datos:

Haz clic en SQL command en el panel izquierdo e introduce el SQL:
CREATE TABLE guestbook (id serial PRIMARY KEY, name text, message text);
INSERT INTO guestbook (name, message) VALUES ('Docker', 'Hello from Compose!');
SELECT * FROM guestbook;

Haz clic en Execute para ejecutar los tres comandos en orden. El último SELECT muestra los datos que acabas de añadir:

Consultar los registros
$ docker compose logs --tail 2
web-1 | 2026/10/13 00:14:23 [notice] 1#1: start worker processes
web-1 | 2026/10/13 00:14:23 [notice] 1#1: start worker process 30
db-1 | 2026-10-13 00:14:24.205 UTC [71] LOG: database system was shut down at 2026-10-13 00:14:24 UTC
db-1 | 2026-10-13 00:14:24.210 UTC [1] LOG: database system is ready to accept connections
adminer-1 | [Tue Oct 13 00:14:22 2026] PHP 8.4.26 Development Server (http://[::]:8080) started
docker compose logs combina y muestra los registros de todos los servicios; cada línea indica a qué servicio pertenece. --tail 2 muestra solo las últimas 2 líneas de cada servicio, -f sigue los registros continuamente y docker compose logs db muestra solo los de db.
Detener e iniciar
$ docker compose stop
[+] stop 3/3
✔ Container compose-demo-adminer-1 Stopped 0.4s
✔ Container compose-demo-web-1 Stopped 0.4s
✔ Container compose-demo-db-1 Stopped 0.3s
$ docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
compose-demo-adminer-1 adminer "entrypoint.sh docke…" adminer 53 seconds ago Exited (0) Less than a second ago
compose-demo-db-1 postgres:18 "docker-entrypoint.s…" db 53 seconds ago Exited (0) Less than a second ago
compose-demo-web-1 nginx:1.30-alpine "/docker-entrypoint.…" web 53 seconds ago Exited (0) Less than a second ago
$ docker compose start
[+] start 3/3
✔ Container compose-demo-db-1 Started 0.3s
✔ Container compose-demo-web-1 Started 1.0s
✔ Container compose-demo-adminer-1 Started 0.4s
stop solo detiene los contenedores (Exited (0)); los contenedores, la red y el Volume siguen ahí. start los inicia de nuevo.
down: eliminar contenedores y conservar los datos
$ docker compose down
[+] down 4/4
✔ Container compose-demo-adminer-1 Removed 0.7s
✔ Container compose-demo-web-1 Removed 0.7s
✔ Container compose-demo-db-1 Removed 0.3s
✔ Network compose-demo_default Removed 0.1s
down elimina los contenedores y la red, pero no elimina el Volume. Al ejecutar up de nuevo, los datos siguen ahí:
$ docker compose up -d
[+] up 4/4
✔ Network compose-demo_default Created 0.1s
✔ Container compose-demo-web-1 Started 0.7s
✔ Container compose-demo-db-1 Started 1.1s
✔ Container compose-demo-adminer-1 Started 1.6s
$ docker compose exec db psql -U postgres -c "SELECT * FROM guestbook;"
id | name | message
----+--------+---------------------
1 | Docker | Hello from Compose!
(1 row)
down -v: eliminar también los datos
$ docker compose down -v
[+] down 5/5
✔ Container compose-demo-adminer-1 Removed 0.7s
✔ Container compose-demo-web-1 Removed 0.7s
✔ Container compose-demo-db-1 Removed 0.2s
✔ Volume compose-demo_pgdata Removed 0.1s
✔ Network compose-demo_default Removed 0.1s
Al añadir -v, también se elimina el Volume compose-demo_pgdata y se pierden los datos de la base de datos. Usa down -v con precaución en producción.
Operaciones básicas
docker compose up -d # Crear e iniciar todos los servicios en segundo plano
docker compose ps # Ver el estado de los servicios
docker compose logs -f # Seguir los registros de todos los servicios
docker compose logs -f db # Ver solo db
docker compose stop # Detener (los contenedores se conservan)
docker compose start # Iniciar de nuevo
docker compose down # Detener y eliminar los contenedores y la red (se conservan los Volume)
docker compose down -v # Eliminar también los Volume (¡se perderán los datos!)
Después de modificar compose.yaml, ejecuta de nuevo docker compose up -d. Compose solo recreará los servicios que hayan cambiado (consulta el ejemplo en comando docker compose).
Nombre del proyecto y nombre del archivo
- De forma predeterminada, el nombre del proyecto es el nombre de la carpeta. También puedes especificar
name: myprojectal principio decompose.yamlo usardocker compose -p myproject. - Compose busca los archivos en este orden:
compose.yaml,compose.yml,docker-compose.yaml,docker-compose.yml. Para proyectos nuevos, se recomienda usarcompose.yaml. version: "3.8"al principio del archivo es una sintaxis antigua. Ya no es necesario y, si lo incluyes, solo aparecerá una advertencia.
Siguiente paso
- Referencia completa de la sintaxis de compose.yaml: build, ports, volumes, environment, depends_on, healthcheck…
- Comandos habituales de docker compose
- Ejercicio práctico: configurar WordPress con Compose
Resumen
- compose.yaml describe varios servicios, redes y Volume; puedes iniciarlos todos con un solo comando.
- Compose crea automáticamente una red para el proyecto. Los servicios se conectan entre sí mediante sus nombres.
docker compose downconserva los Volume;down -velimina los datos.- Docker Desktop muestra los proyectos de Compose agrupados.
Ejercicios
Ejercicio 1: En el proyecto de este capítulo, usa un solo comando para ver las últimas 5 líneas de los registros del servicio db.
Respuesta
docker compose logs --tail 5 db
Ejercicio 2: Después de ejecutar docker compose down y luego up -d, ¿siguen estando las tablas creadas en Adminer? ¿Y si usas down -v?
Respuesta
Después de down, los datos siguen ahí porque se conserva el Volume pgdata; down -v elimina el Volume y la base de datos se inicializa de nuevo, por lo que las tablas desaparecen.
Preguntas frecuentes
¿Cuál es la diferencia entre docker-compose y docker compose?
docker-compose (con guion) es el programa independiente v1, cuyo mantenimiento ya se ha discontinuado; ahora se usa el plugin de Docker CLI docker compose (con espacio). Este tutorial usa la v5.
¿Se pueden usar tanto compose.yaml como docker-compose.yml?
Sí, Compose los busca en orden. Para los proyectos nuevos se recomienda compose.yaml.
¿Cómo se determina el nombre del proyecto?
De forma predeterminada, es el nombre de la carpeta que contiene compose.yaml. Los nombres de los contenedores, la red y los Volume llevarán ese nombre como prefijo. Puedes especificarlo con name: o -p.
Actualizado 14 de octubre de 2026