Docker Compose en 2026: Aplicaciones Multi-Contenedor, Redes y Preguntas de Entrevista DevOps

Guía completa sobre Docker Compose en 2026 que cubre aplicaciones multi-contenedor, configuración avanzada de redes y preguntas frecuentes en entrevistas DevOps.

Docker Compose Multi-Container Tutorial 2026

Docker Compose continúa siendo la herramienta de referencia para definir y ejecutar aplicaciones Docker multi-contenedor en 2026. Ya sea orquestando un stack de desarrollo local o preparándose para una entrevista DevOps, el dominio de las redes Compose, las dependencias de servicios y los patrones de producción diferencia a los ingenieros junior de los profesionales senior.

Punto Clave

Docker Compose utiliza un formato YAML declarativo para definir servicios, redes y volúmenes en un único archivo. Ejecutar docker compose up levanta toda la pila de la aplicación con redes aisladas y almacenamiento persistente.

Entendiendo la Arquitectura de Docker Compose

Docker Compose opera bajo un principio simple: definir los servicios de la aplicación en un archivo compose.yaml (la convención de nomenclatura moderna que reemplaza docker-compose.yml), y Compose se encarga de la creación de contenedores, las redes y la gestión del ciclo de vida.

La especificación de Docker Compose define tres conceptos fundamentales:

  • Servicios: Configuraciones de contenedores incluyendo imagen, contexto de build, variables de entorno y límites de recursos
  • Redes: Canales de comunicación aislados entre servicios
  • Volúmenes: Almacenamiento de datos persistente que sobrevive a los reinicios de contenedores
yaml
# compose.yaml
services:
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/app
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend

  db:
    image: postgres:16
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=app
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - backend

networks:
  backend:
    driver: bridge

volumes:
  postgres_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Esta configuración demuestra varios patrones listos para producción: health checks para el ordenamiento de dependencias, secrets de Docker para datos sensibles, volúmenes nombrados para persistencia y definiciones de red explícitas.

Redes de Docker Compose en Profundidad

Por defecto, Compose crea una única red para la aplicación. Todos los servicios se unen a esta red y pueden alcanzarse mutuamente usando el nombre del servicio como hostname. Entender este modelo de red es fundamental para una migración a Kubernetes posterior.

yaml
# compose.yaml
services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    networks:
      - frontend-net
      - backend-net

  api:
    build: ./api
    networks:
      - backend-net

  cache:
    image: redis:7-alpine
    networks:
      - backend-net

  db:
    image: postgres:16
    networks:
      - backend-net

networks:
  frontend-net:
    driver: bridge
  backend-net:
    driver: bridge
    internal: true

El flag internal: true impide que la red backend acceda a Internet externo. El servicio frontend conecta ambas redes, actuando como único punto de entrada. Esta segmentación de red refleja las prácticas de seguridad en producción.

Resolución DNS

El servidor DNS embebido de Docker resuelve automáticamente los nombres de servicio. El servicio api alcanza la base de datos en db:5432 sin ninguna configuración manual de IP.

Builds Multi-Etapa con Compose

Las imágenes de producción deben ser mínimas. Los builds multi-etapa combinados con perfiles de Compose permiten diferentes configuraciones para desarrollo y producción.

dockerfile
# api/Dockerfile
# Etapa 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Etapa 2: Producción
FROM node:22-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

# Etapa 3: Desarrollo
FROM node:22-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
USER node
CMD ["npm", "run", "dev"]
yaml
# compose.yaml
services:
  api:
    build:
      context: ./api
      target: ${BUILD_TARGET:-production}
    volumes:
      - ${API_VOLUMES:-./api/dist:/app/dist:ro}
    profiles:
      - ${COMPOSE_PROFILES:-prod}

Ejecutar BUILD_TARGET=development COMPOSE_PROFILES=dev docker compose up inicia la configuración de desarrollo con recarga en caliente.

Dependencias de Servicios y Health Checks

La directiva depends_on controla el orden de inicio, pero que los contenedores inicien no significa que los servicios estén listos. Los health checks resuelven este problema de timing—un patrón frecuentemente preguntado en entrevistas DevOps.

yaml
# compose.yaml
services:
  api:
    build: ./api
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
      migrations:
        condition: service_completed_successfully

  migrations:
    build: ./api
    command: npm run migrate
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

  cache:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 3

Existen tres condiciones de dependencia:

  • service_started: Por defecto, el contenedor ha iniciado
  • service_healthy: El health check pasa
  • service_completed_successfully: El contenedor termina con código 0 (para contenedores de inicialización)

¿Listo para aprobar tus entrevistas de DevOps?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Docker Compose para Desarrollo Local

Los entornos de desarrollo se benefician de bind mounts, overrides de entorno y herramientas de depuración. El archivo compose.override.yaml se fusiona automáticamente con compose.yaml.

yaml
# compose.yaml (configuración base)
services:
  api:
    build: ./api
    environment:
      - NODE_ENV=production

  db:
    image: postgres:16
yaml
# compose.override.yaml (overrides de desarrollo)
services:
  api:
    build:
      target: development
    volumes:
      - ./api:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DEBUG=app:*
    ports:
      - "9229:9229"

  db:
    ports:
      - "5432:5432"

El volumen anónimo /app/node_modules evita que el node_modules del host sobrescriba las dependencias instaladas del contenedor.

Patrones de Despliegue en Producción

Docker Compose funciona para despliegues de producción en un solo host. Para orquestación multi-host, Kubernetes con Helm proporciona mejor escalabilidad, pero Compose sigue siendo viable para aplicaciones más pequeñas.

yaml
# compose.prod.yaml
services:
  api:
    image: registry.example.com/api:${VERSION:-latest}
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - api

La clave deploy configura límites de recursos, cantidad de réplicas y políticas de reinicio. Ejecutar docker compose -f compose.prod.yaml up -d inicia el stack de producción en modo desconectado.

Variables de Entorno y Gestión de Secrets

La configuración sensible requiere un manejo apropiado. Docker Compose soporta múltiples enfoques, desde archivos .env hasta secrets de Docker.

bash
# .env
POSTGRES_PASSWORD=dev_password_only
API_SECRET_KEY=local_dev_key
yaml
# compose.yaml
services:
  api:
    environment:
      - API_SECRET_KEY  # Hereda del shell o .env
      - DATABASE_URL=postgres://user:${POSTGRES_PASSWORD}@db:5432/app
    env_file:
      - ./config/api.env

Para producción, los secrets de Docker proporcionan mejor seguridad al montar datos sensibles como archivos en lugar de variables de entorno:

yaml
# compose.prod.yaml
services:
  api:
    secrets:
      - api_key
      - db_password
    environment:
      - API_KEY_FILE=/run/secrets/api_key

secrets:
  api_key:
    external: true
  db_password:
    file: ./secrets/db_password.txt
Nota de Seguridad

Nunca hacer commit de archivos .env que contengan secrets de producción al control de versiones. Usar soluciones externas de gestión de secrets como HashiCorp Vault o soluciones de proveedores cloud para despliegues de producción.

Preguntas Comunes de Entrevista DevOps sobre Docker Compose

Los entrevistadores evalúan la comprensión de conceptos de Compose a través de escenarios prácticos. Estas preguntas aparecen frecuentemente en entrevistas de DevOps e ingeniería de plataformas.

P: ¿Cómo se comunican los contenedores en una red de Compose?

Docker crea una red bridge dedicada para cada proyecto Compose. Los servicios se comunican usando sus nombres de servicio como hostnames. El servidor DNS embebido resuelve estos nombres a direcciones IP de contenedores. El tráfico externo alcanza los servicios solo a través de puertos explícitamente publicados.

P: ¿Qué sucede cuando se ejecuta docker compose up con contenedores existentes?

Compose compara la configuración actual contra los contenedores en ejecución. Los servicios sin cambios continúan ejecutándose. Los servicios modificados se recrean con las nuevas configuraciones. Los nuevos servicios se inician desde cero. Los servicios eliminados se detienen y eliminan.

P: ¿Cómo se manejan las migraciones de base de datos en Compose?

Existen dos patrones. Primero, usar un contenedor de inicialización con dependencia service_completed_successfully:

yaml
services:
  migrate:
    image: api:latest
    command: npm run migrate
    depends_on:
      db:
        condition: service_healthy

  api:
    depends_on:
      migrate:
        condition: service_completed_successfully

Segundo, incluir la lógica de migración en el script de inicio de la aplicación, verificando y aplicando migraciones pendientes antes de aceptar tráfico.

P: ¿Cuál es la diferencia entre volúmenes y bind mounts?

Los volúmenes nombrados son gestionados por Docker, almacenados en /var/lib/docker/volumes, y portables entre hosts. Los bind mounts mapean directorios del host directamente en contenedores, útiles para desarrollo pero dependientes del entorno. Los volúmenes soportan drivers para almacenamiento remoto como NFS o almacenamiento en bloques en la nube.

P: ¿Cuál es la diferencia entre docker-compose y docker compose?

El docker-compose con guion era la herramienta standalone V1 basada en Python, ahora deprecada. El docker compose con espacio es la implementación V2 basada en Go integrada en el CLI de Docker. V2 es más rápido, soporta completamente la Especificación de Compose y recibe desarrollo activo.

Depuración de Aplicaciones Compose

La resolución de problemas en aplicaciones contenedorizadas requiere técnicas específicas. Estos comandos revelan lo que está sucediendo dentro del stack de Compose:

bash
# Ver logs de todos los servicios
docker compose logs -f

# Logs de un servicio específico con timestamps
docker compose logs -f --timestamps api

# Ejecutar comando en contenedor en ejecución
docker compose exec api sh

# Ejecutar comando único (inicia nuevo contenedor)
docker compose run --rm api npm test

# Ver uso de recursos
docker compose top
docker stats

# Inspeccionar configuración de red
docker network inspect project_backend

# Validar archivo compose
docker compose config

El comando docker compose config fusiona todos los archivos compose y muestra la configuración final—invaluable para depurar problemas de interpolación de variables.

Conclusión

  • Docker Compose define aplicaciones multi-contenedor en un único archivo YAML con servicios, redes y volúmenes
  • Los servicios se comunican vía DNS usando nombres de servicio como hostnames dentro de la red bridge por defecto
  • Los health checks con condiciones service_healthy aseguran un ordenamiento de inicio correcto
  • Usar compose.override.yaml para configuraciones específicas de desarrollo como bind mounts y puertos de depuración
  • Los despliegues de producción se benefician de límites de recursos, políticas de reinicio y secrets de Docker para datos sensibles
  • El CLI docker compose (V2) reemplaza al deprecado docker-compose (V1) con mejor rendimiento y características

¡Empieza a practicar!

Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.

Etiquetas

#docker
#docker-compose
#devops
#containers
#networking

Compartir

Artículos relacionados