← maurobernal.com.ar

Etiqueta: compose

  • Docker Compose: el día que dejé de levantar contenedores a mano

    Tenía un script Bash con 8 comandos docker run. Cada vez que alguien del equipo necesitaba levantar el entorno de desarrollo, le mandaba el script por Slack y rezaba para que no hubiera cambiado nada desde la última vez. Un día un compañero me mostró su docker-compose.yml. Nunca más volví al script.

    ¿Qué es Docker Compose?

    Docker Compose es una herramienta para definir y ejecutar aplicaciones multi-contenedor usando un archivo YAML. En lugar de recordar 8 comandos docker run con todos sus flags, definís todos los servicios, redes y volúmenes en un solo archivo versionado. Un comando levanta todo; otro lo baja.

    El docker-compose.yml completo: .NET + PostgreSQL + Redis + Nginx

    Este es el stack que uso como base en mis proyectos. Cada servicio tiene su rol claro:

    version: '3.8'
    
    services:
      # Proxy inverso - único punto de entrada
      nginx:
        image: nginx:1.25-alpine
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
          - ./nginx/certs:/etc/nginx/certs:ro
        depends_on:
          - api
        restart: unless-stopped
    
      # API .NET 8
      api:
        build:
          context: .
          dockerfile: Dockerfile
        environment:
          - ASPNETCORE_ENVIRONMENT=Production
          - ConnectionStrings__Default=Host=postgres;Database=miapp;Username=app;Password=${DB_PASSWORD}
          - Redis__ConnectionString=redis:6379
        depends_on:
          postgres:
            condition: service_healthy
          redis:
            condition: service_started
        restart: unless-stopped
        # Sin -p: solo accesible internamente a través de nginx
    
      # Base de datos PostgreSQL
      postgres:
        image: postgres:16-alpine
        environment:
          POSTGRES_DB: miapp
          POSTGRES_USER: app
          POSTGRES_PASSWORD: ${DB_PASSWORD}
        volumes:
          - postgres-data:/var/lib/postgresql/data
          - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U app -d miapp"]
          interval: 10s
          timeout: 5s
          retries: 5
        restart: unless-stopped
    
      # Cache Redis
      redis:
        image: redis:7-alpine
        command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
        volumes:
          - redis-data:/data
        restart: unless-stopped
    
    volumes:
      postgres-data:
      redis-data:
    
    networks:
      default:
        name: miapp-network

    El archivo .env: secretos fuera del YAML

    # .env (en .gitignore - nunca en el repo)
    DB_PASSWORD=password-super-seguro-aqui
    REDIS_PASSWORD=otro-password-seguro

    Los comandos que uso todos los días

    # Levantar todo en background
    docker compose up -d
    
    # Levantar y ver los logs mientras arranca
    docker compose up
    
    # Levantar solo un servicio (y sus dependencias)
    docker compose up -d api
    
    # Ver estado de los servicios
    docker compose ps
    
    # Logs de todos los servicios
    docker compose logs -f
    
    # Logs de un servicio específico
    docker compose logs -f api
    
    # Ejecutar comando en un servicio
    docker compose exec api bash
    docker compose exec postgres psql -U app -d miapp
    
    # Bajar todo (mantiene volúmenes)
    docker compose down
    
    # Bajar y eliminar volúmenes (¡CUIDADO en producción!)
    docker compose down -v
    
    # Rebuild y restart de un servicio
    docker compose up -d --build api
    
    # Escalar un servicio (múltiples instancias)
    docker compose up -d --scale api=3

    Health checks: que Compose espere a que los servicios estén listos

    Uno de los problemas clásicos: la API arranca antes que la base de datos y falla al conectar. La solución está en los healthcheck y depends_on con condición, como hice en el ejemplo de Postgres. Compose espera hasta que el healthcheck pase antes de arrancar los servicios dependientes.

    # Verificar el healthcheck de un servicio
    docker compose ps
    # NAME              STATUS
    # miapp-postgres-1  healthy   ← Postgres superó el healthcheck
    # miapp-api-1       running   ← API arrancó después

    El antes y el después

    Mi script Bash antes:

    # ❌ Lo que tenía antes (8 líneas que siempre tenía que recordar actualizar)
    docker network create miapp
    docker run -d --name postgres --network miapp -e POSTGRES_PASSWORD=... ...
    docker run -d --name redis --network miapp ...
    docker run -d --name api --network miapp -e DB_HOST=postgres ...
    docker run -d --name nginx --network miapp -p 80:80 ...
    # etc...

    Ahora:

    # ✅ Todo el stack en un comando
    docker compose up -d

    El archivo está en el repo. Cualquier miembro del equipo puede clonar y levantar el entorno completo en un comando. Sin documentación de «cómo levantar el entorno». Sin scripts que se desactualizan. El docker-compose.yml es la documentación.


    Artículo anterior: Redes en Docker | Serie Docker Completo | Próximo: Entornos consistentes →


    Artículo anterior: Redes en Docker: de ‘no puedo conectar mis contenedores’ a entenderlo de verdad | Serie Docker Completo | Próximo: Cómo uso Docker para tener el mismo entorno en dev, test y producción →

Tags

tsql (27)mssql (26)sql (20)devops (20)dotnet (18)docker (15)performance (14)contenedores (11)dotnet10 (10)linux (9)csharp (8)microservicios (7)angular (7)angular21 (7)sql server (6)issabel (6)docker-compose (6)typescript (6)mysql (5).NET (5)