Docker Compose healthchecks: depends_on, secretos y .env
Cómo escribir healthchecks correctos en Docker Compose, usar depends_on con condition: service_healthy, gestionar secretos con .env.example y no exponer puertos de base de datos.
Compose moderno: sin version:
En Docker Compose v2 la clave version: está obsoleta. Compose la ignora y emite un aviso. Los archivos modernos empiezan directamente por services: y, si hace falta, declaran volumes: y networks: al mismo nivel.
Healthchecks por servicio
Un healthcheck le dice a Docker si un servicio está realmente listo, no solo si el proceso arrancó. Es la base para que depends_on pueda esperar de forma fiable. Los comandos referencian variables del propio contenedor con $$VAR: Compose convierte $$ en un único $, que el shell del contenedor evalúa en tiempo de ejecución (donde la variable del servicio sí existe).
- PostgreSQL:
pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB - MySQL:
mysqladmin ping -h localhost -u $$MYSQL_USER -p$$MYSQL_PASSWORD - Redis:
redis-cli ping(con-a "$$REDIS_PASSWORD"si hay contraseña) - HTTP / web:
wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
depends_on con condition: service_healthy
La forma corta de depends_on (una lista) solo garantiza el orden de arranque. Para esperar a que la dependencia esté sana, usa la forma larga:
services:
app:
build: .
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20sSecretos y .env.example
Nunca pongas contraseñas literales en el compose.yaml: acaban en el repositorio y en el historial de git. Usa ${VARIABLE} en environment y define los valores en un .env que no se commitea. Versiona solo un .env.example con placeholders como CHANGE_ME para documentar qué variables hacen falta.
Puertos de base de datos: local frente a producción
Publicar 5432:5432 o 3306:3306 expone la base de datos a toda la red del host. En desarrollo, si necesitas conectarte desde el host, bindea a loopback (127.0.0.1:5432:5432). En producción, mantén la base de datos en la red interna de Compose y no publiques su puerto: los demás servicios la alcanzan por su nombre.
Volúmenes y backups
Los datos de una base de datos deben vivir en un volumen con nombre (por ejemplo postgres_data:/var/lib/postgresql/data) para que sobrevivan a docker compose down. Un volumen no es un backup: programa volcados periódicos (pg_dump, mysqldump) y guárdalos fuera del host. Para Nginx como reverse proxy, monta la configuración en solo lectura (./nginx.conf:/etc/nginx/nginx.conf:ro).
Siguientes pasos
Genera un compose.yaml de partida y valida el tuyo con el generador y validador de Docker Compose. Construye healthchecks listos para pegar y comprueba que tu Compose no expone puertos ni secretos por error.
Preguntas frecuentes
- ¿Cómo escribo un healthcheck para Postgres en Docker Compose?
- Usa pg_isready dentro del propio contenedor: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]. El doble $$ le dice a Compose que pase un único $ al contenedor, donde POSTGRES_USER y POSTGRES_DB existen como variables de entorno del servicio. Acompáñalo de interval, timeout, retries y start_period.
- ¿Por qué depends_on no espera a que la base de datos esté lista?
- La forma corta de depends_on (una lista de nombres) solo espera a que el contenedor arranque, no a que el servicio acepte conexiones. Para esperar de verdad necesitas un healthcheck en el servicio destino y la forma larga: depends_on con condition: service_healthy.
- ¿Dónde pongo las contraseñas de mi compose.yaml?
- En un archivo .env que NO se commitea. En el compose.yaml referencia las variables con ${VARIABLE} y versiona solo un .env.example con placeholders (por ejemplo CHANGE_ME). Así el secreto real nunca entra en git ni en su historial.
- ¿Debo exponer el puerto de la base de datos?
- En producción, no: deja la base de datos en la red interna de Compose y conéctate desde los otros servicios por su nombre. En desarrollo, si necesitas acceder desde el host, bindea a 127.0.0.1 (127.0.0.1:5432:5432) para no abrirla a toda la red.
- ¿Hace falta la clave version: en Compose moderno?
- No. En Docker Compose v2 la clave version: está obsoleta: se ignora y genera un aviso. Empieza el archivo directamente por services:.