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 usa docker 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:

ServicioFunción
webnginx, usa la carpeta ./site como sitio web, en el puerto 8080 del host
dbPostgreSQL 18; los datos se guardan en un Volume llamado pgdata (ten en cuenta que la versión 18 monta /var/lib/postgresql; consulta Volume)
adminerHerramienta 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 pgdata es compose-demo_pgdata.
  • db no tiene ports configurado, así que el campo PORTS solo muestra 5432/tcp y no se puede acceder desde el exterior.

Abre http://localhost:8080:

nginx iniciado por Compose muestra site/index.html
El servicio web muestra el contenido de site/index.html

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:

Pantalla de inicio de sesión de Adminer; System está configurado como MySQL de forma predeterminada
Configuración predeterminada de Adminer: System es MySQL / MariaDB y Server ya tiene el valor db

Inicia sesión con la siguiente configuración:

CampoValor
SystemPostgreSQL (debes cambiarlo; de lo contrario, intentará conectarse como MySQL y fallará)
Serverdb (nombre del servicio, resuelto a través de la red de Compose)
Usernamepostgres
Passwordexample (POSTGRES_PASSWORD en compose.yaml)
Pantalla de inicio de sesión de Adminer con PostgreSQL seleccionado en System
Después de cambiar System a PostgreSQL, haz clic en Login

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

Tras iniciar sesión en Adminer, se muestran la versión de PostgreSQL y la lista de bases de datos
Adminer se conecta a PostgreSQL del servicio db a través de la red de Compose

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;
Pantalla para introducir SQL en SQL command de Adminer
Introduce el SQL en SQL command y haz clic en Execute

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

Resultado de ejecutar SQL en Adminer
Crear una tabla, añadir un registro y consultar el resultado

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: myproject al principio de compose.yaml o usar docker 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 usar compose.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

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 down conserva los Volume; down -v elimina 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