← maurobernal.com.ar

Docker Compose de cero a producción — Parte 1: Qué es y cómo funciona

Antes de Docker Compose, levantar un entorno de desarrollo con varios servicios era un ritual de paciencia. Un docker run para la base de datos, otro para el backend, otro para Redis, acordarse de los flags de red, los volúmenes, las variables de entorno… y rezar para que el próximo dev del equipo pudiera repetir exactamente los mismos pasos.

Docker Compose resolvió todo eso con un solo archivo YAML y un comando. En esta primera parte de la serie te cuento qué es, de dónde viene y cómo se estructura ese archivo que se vuelve la única fuente de verdad de tu entorno.

¿Qué es Docker Compose y por qué importa?

Docker Compose es una herramienta diseñada para definir y ejecutar aplicaciones que constan de múltiples contenedores. Su propósito es simple pero poderoso: en lugar de gestionar cada contenedor con comandos individuales, describís el estado deseado de todo el sistema en un archivo compose.yaml, y Compose se encarga de alcanzar ese estado.

Los beneficios que más uso en el día a día:

  • Entornos reproducibles: el clásico «funciona en mi máquina» desaparece. Si el entorno está en código, todos ejecutan lo mismo.
  • Onboarding en minutos: un nuevo dev solo necesita Docker instalado. Un docker compose up y tiene todo funcionando.
  • IaC a nivel desarrollador: el compose.yaml vive junto al código en Git. El entorno es versionable, revisable y auditable.
  • Ciclos rápidos: Compose reutiliza contenedores que no cambiaron. Los reinicios son rápidos.

De Fig a Compose V2: una historia corta pero importante

Docker Compose no nació en Docker. Empezó como Fig, un proyecto de la empresa Orchardup que ya ofrecía exactamente esta idea: definir y levantar entornos multi-contenedor con un archivo YAML. Docker Inc. vio el valor, adquirió Orchardup en 2013 y relanzó Fig como Docker Compose.

Hoy existen dos versiones del CLI que vale la pena distinguir:

CaracterísticaV1 (legado)V2 (actual)
Comandodocker-compose (con guion)docker compose (sin guion)
LenguajePythonGo
Campo version:Requerido (2.0 a 3.8)Ignorado (usa Compose Spec)
IntegraciónBinario separadoPlugin del Docker CLI

Si encontrás documentación con docker-compose (con guion) y version: '3.8' en la primera línea, es sintaxis de V1. Todo el contenido de esta serie usa V2, que es el estándar actual.

El archivo compose.yaml: la única fuente de verdad

El corazón de Docker Compose es su archivo de configuración. Puede llamarse compose.yaml (preferido), compose.yml, docker-compose.yaml o docker-compose.yml — todos son reconocidos por compatibilidad.

Las directivas de nivel superior que vas a usar en prácticamente todo proyecto:

# compose.yaml
services:     # Los contenedores de tu aplicación (obligatorio)
networks:     # Redes personalizadas entre servicios (opcional)
volumes:      # Volúmenes nombrados para persistencia (opcional)
secrets:      # Datos sensibles (contraseñas, claves API) (opcional)
configs:      # Configuración no sensible externa a la imagen (opcional)

Definiendo servicios

Cada servicio representa un componente de tu aplicación corriendo en uno o más contenedores. Los atributos que más uso:

services:
  web:
    image: nginx:alpine            # Imagen de Docker Hub
    container_name: mi_nginx       # Nombre personalizado (cuidado si escalás)
    ports:
      - "8080:80"                  # host:contenedor
    environment:
      APP_ENV: production
    env_file:
      - .env                       # Variables desde archivo (no versionarlo con secretos)
    restart: unless-stopped        # Reinicio automático excepto si lo detenés manualmente

  api:
    build:                         # Construir desde Dockerfile en lugar de usar imagen
      context: .
      dockerfile: Dockerfile
      args:
        - NODE_VERSION=20          # ARGs del Dockerfile
      target: production           # Para builds multi-stage
    command: ["npm", "start"]      # Sobrescribe CMD del Dockerfile
    depends_on:
      - db                         # Arranca después de 'db'
    
  db:
    image: postgres:15-alpine
    volumes:
      - pg_data:/var/lib/postgresql/data   # Volumen nombrado para persistencia

La flexibilidad de elegir entre image y build es clave: usás imagen oficial para componentes estándar (Postgres, Redis, Nginx) y build para tu código propio. Pueden convivir sin problema en el mismo archivo.

Redes: cómo se comunican los servicios

Cuando levantás un proyecto con docker compose up, Compose crea automáticamente una red bridge y conecta todos los servicios a ella. La magia: los servicios se encuentran entre sí usando su nombre como hostname DNS.

services:
  api:
    image: mi-api
    environment:
      # 'db' es el nombre del servicio, funciona como hostname
      DB_HOST: db
      REDIS_HOST: cache

  db:
    image: postgres:15

  cache:
    image: redis:alpine

Para mayor control, podés definir redes personalizadas y segmentar qué servicios pueden verse entre sí:

services:
  frontend:
    networks: [public]             # Solo en la red pública

  api:
    networks: [public, internal]   # En ambas redes

  db:
    networks: [internal]           # Solo en la red interna, no expuesta al exterior

networks:
  public:
    driver: bridge
  internal:
    driver: bridge
    internal: true                 # Sin acceso al exterior

Volúmenes: persistencia de datos

Por defecto, los datos dentro de un contenedor desaparecen cuando el contenedor se elimina. Los volúmenes resuelven esto. Hay dos tipos que uso constantemente:

services:
  db:
    image: postgres:15
    volumes:
      # Tipo 1: Volumen nombrado — Docker gestiona el almacenamiento
      # Ideal para producción y datos de base de datos
      - pg_data:/var/lib/postgresql/data

  api:
    build: .
    volumes:
      # Tipo 2: Bind mount — mapea un directorio del host al contenedor
      # Ideal para desarrollo: cambios en el código se reflejan al instante
      - .:/usr/src/app

# Los volúmenes nombrados se declaran en el nivel superior
volumes:
  pg_data:
    driver: local

La regla que sigo: volúmenes nombrados para datos que deben persistir (bases de datos, uploads, logs), bind mounts para el código fuente durante el desarrollo para tener hot-reload sin reconstruir la imagen.

Resumen de la Parte 1

  • Docker Compose define entornos multi-contenedor en un solo archivo declarativo
  • Usá siempre V2 (docker compose sin guion); el campo version: ya no es necesario
  • Los servicios se comunican usando su nombre como hostname — no necesitás IPs ni configuración manual
  • Volúmenes nombrados para persistencia, bind mounts para desarrollo ágil

En la Parte 2 vemos los comandos esenciales del CLI y las características que hacen que los entornos sean robustos: depends_on con healthchecks, escalado y perfiles.

Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.