El archivo docker-compose.yml es el plano de tu arquitectura. Es un archivo de texto escrito en formato YAML.
Un archivo de Docker Compose tiene 3 bloques principales de alto nivel:
services: (Obligatorio) Los contenedores que vamos a lanzar.volumes: (Opcional) Los “discos duros” persistentes que vamos a crear.networks: (Opcional) Las redes personalizadas para conectar todo.
Vamos a verlos uno por uno.
En YAML, la indentación es sagrada. No se usan llaves {} ni puntos y coma ;. La jerarquía se define con espacios (normalmente 2 espacios por nivel).
Nunca uses tabuladores. Si mezclas espacios y tabuladores, Docker te dará un error y no sabrás por qué.
El bloque services
Aquí es donde definimos nuestros contenedores. Cada elemento dentro de services es un contenedor (o una réplica de ellos).
La mejor forma de entenderlo es “traduciendo” un comando docker run. Imagina este comando que ya dominas:
docker run -d \
--name mi-web \
-p 8080:80 \
-v ./html:/usr/share/nginx/html \
nginx:alpine
¿Cómo se escribiría esto en Compose?
services:
mi-web: # Nombre del servicio (Servirá como DNS interno)
image: nginx:alpine # Imagen base
container_name: mi-web # Opcional: Fuerza un nombre específico
ports:
- "8080:80" # Lista de puertos (Host:Container)
volumes:
- ./html:/usr/share/nginx/html # Volúmenes o Bind Mounts
¿Ves la similitud? Es lo mismo, pero bastante más ordenado.
Claves principales dentro de un servicio:
image: Qué imagen usar (ej:mysql:5.7).build: Si en vez de descargar una imagen quieres construirla desde unDockerfile(lo veremos más adelante).ports: Lista de mapeo de puertos (HOST:CONTAINER). Importante: Usa siempre comillas"80:80"para evitar que YAML interprete números bajos (como el puerto 60) como base sexagesimal.environment: Variables de entorno (equivalente a-e).volumes: Mapeo de discos (equivalente a-v).restart: Política de reinicio.restart: alwayshará que si el contenedor se cae, Docker lo levante solo. ¡Magia!
El bloque volumes
Si en tus servicios usas un Bind Mount (una ruta de tu PC ./carpeta:/datos), no necesitas declarar nada más.
Pero si quieres usar Volúmenes gestionados (la forma correcta para Bases de Datos), debes declararlos al final del archivo como un recurso global.
services:
base-datos:
image: postgres
volumes:
- db-data:/var/lib/postgresql/data # Uso el volumen 'db-data'
volumes:
db-data: # ¡Declaro que este volumen existe!
Si no pones el bloque volumes: al final, Docker te dará un error diciendo que el volumen db-data no está definido.
El bloque networks
Por defecto Docker Compose crea automáticamente una red única para tu proyecto y mete todos los servicios en ella.
Esto significa que si tienes un servicio web y un servicio db, pueden hacerse ping mutuamente usando sus nombres (ping db) sin que tú configures nada.
Pero si quieres aislar cosas (ej: red frontend y red backend), puedes declararlas explícitamente.
services:
web:
image: nginx
networks:
- red-frontend
db:
image: mysql
networks:
- red-backend
networks:
red-frontend:
red-backend:
Ejemplo completo
Vamos a juntar todo en un ejemplo real. Una aplicación web que usa una base de datos MySQL y phpMyAdmin para gestionarla.
version: '3.8' # Versión del formato
services:
# Servicio 1: La Base de Datos
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password123
MYSQL_DATABASE: mi_app
volumes:
- mysql-data:/var/lib/mysql
networks:
- backend-net
# Servicio 2: El gestor visual (phpMyAdmin)
admin:
image: phpmyadmin/phpmyadmin
ports:
- "8080:80"
environment:
PMA_HOST: db # Usamos el nombre del otro servicio
depends_on:
- db # Espera a que 'db' arranque antes de iniciar este
networks:
- backend-net
volumes:
mysql-data: # Volumen persistente para que la DB no se borre
networks:
backend-net: # Red privada
¿Qué acabamos de definir?
Con este simple archivo de texto, hemos definido:
- Dos servidores (
dbyadmin). - Una red privada donde se comunican.
- Un volumen persistente para los datos.
- La configuración de contraseñas y puertos.
- Las dependencias de arranque (
depends_on).
Ahora, solo tendríamos que guardar esto como docker-compose.yml y ejecutar docker compose up -d. ¡Bum! Sistema desplegado.
No subas secretos ni contraseñas
En el ejemplo he puesto password123. Eso está mal, es solo para el ejemplo. Si subes este archivo a GitHub, te han hackeado.
Veremos como tratar correctamente contraseñas en la siguiente entrada
