Cheatsheet 04

Docker Compose

Un archivo YAML que describe todos los contenedores de tu proyecto y cómo se conectan. Un solo comando lo levanta todo.

1

Qué pasa con docker compose up

Del YAML a contenedores, red y volumen.

docker-compose.yml services: chanchito: build: . ports: 3000:3000 monguito: image: mongo ports: 27017:27017 environment: … volumes: mongo-data:… volumes: mongo-data: up red automática: pruebas-docker_default chanchito imagen construida del Dockerfile pruebas-docker-chanchito :3000 monguito imagen oficial mongo /data/db :27017 monguito:27017 cada servicio se alcanza por su nombre de servicio — no hace falta links mongo-data volumen tu PC → localhost:3000 · localhost:27017
i

El prefijo pruebas-docker_ sale del nombre de la carpeta (nombre del proyecto). Cambialo con -p <nombre> o con name: arriba del YAML.

2

Comandos de compose

Se ejecutan en la carpeta del docker-compose.yml.

Levantar y bajar

docker compose up
Construye (si hace falta), crea y arranca todo. Logs en la terminal.
docker compose up -d
En segundo plano.
docker compose up --build
Fuerza el rebuild de las imágenes (cuando cambiaste el Dockerfile o el código en prod).
docker compose down
Detiene y borra contenedores y red. Los volúmenes quedan.
docker compose down -v
Además borra los volúmenes (se pierden los datos de la DB).

Usar otro archivo

docker compose -f docker-compose-dev.yml up
Compose custom: -f va antes de up.
docker compose -f docker-compose-dev.yml down
Para bajarlo usá el mismo -f.
docker compose -f docker-compose.yml -f docker-compose.override.yml up
Combinar archivos (el segundo pisa al primero).
docker compose config
Muestra el YAML final resuelto (con variables). Ideal para detectar errores.

Operar servicios

docker compose ps
Estado de los servicios del proyecto.
docker compose logs -f chanchito
Logs de un servicio (sin nombre: de todos).
docker compose exec chanchito sh
Terminal dentro de un servicio (usa el nombre del servicio).
docker compose restart chanchito
Reiniciar uno.
docker compose stop
docker compose start
Detener / arrancar sin borrar.
docker compose build chanchito
Solo construir la imagen.
!

docker compose (con espacio) es la versión actual integrada en Docker. docker-compose (con guion) es la v1, ya discontinuada.

3

Claves del YAML

Lo que va dentro de cada servicio.

Referencia de claves

ClavePara quéEjemplo
servicesLos contenedores a crear (uno por clave)services: chanchito: …
buildConstruir desde un Dockerfile. Forma corta = carpeta; forma larga = context + dockerfilebuild: .
imageUsar una imagen ya hecha (Docker Hub)image: mongo:7
portsMapeo "HOST:CONTENEDOR" (entre comillas)- "3000:3000"
environmentVariables de entorno- NODE_ENV=production
env_fileVariables desde archivoenv_file: .env
volumesVolúmenes nombrados o bind mounts- mongo-data:/data/db · - .:/home/app
depends_onOrden de arranque (este arranca después de…)depends_on: [monguito]
linksLegacy. Ya no hace falta: la red de compose resuelve por nombre- monguito
restartReinicio automáticorestart: unless-stopped
commandPisa el CMD del Dockerfilecommand: npm run dev
container_nameNombre fijo del contenedorcontainer_name: monguito
networksRedes personalizadas (opcional)networks: [backend]
volumes (raíz)Declara los volúmenes nombradosvolumes: mongo-data:
!

version: "3.9" al principio del archivo es obsoleto: Compose v2 lo ignora y muestra un warning. Podés borrarlo.

i

YAML usa espacios, nunca tabs. La indentación define la jerarquía; mantené siempre el mismo ancho (2 o 4 espacios).

4

Compose de producción

La imagen lleva el código adentro (Dockerfile con COPY).

Comentado

docker-compose.yml

docker-compose.ymldocker compose up
services:

  # Contenedor de nuestra aplicación
  chanchito:
    build: .              # busca el Dockerfile en la carpeta actual
    ports:
      - "3000:3000"       # PC:3000 -> contenedor:3000
    links:
      - monguito          # (legacy) chanchito habla con monguito

  # Contenedor de MongoDB
  monguito:
    image: mongo          # imagen oficial
    ports:
      - "27017:27017"
    environment:          # crea el usuario admin al iniciar
      - MONGO_INITDB_ROOT_USERNAME=mati
      - MONGO_INITDB_ROOT_PASSWORD=<password>
    volumes:
      - mongo-data:/data/db   # persiste los datos
      # mysql    -> /var/lib/mysql
      # postgres -> /var/lib/postgresql/data

# Declaración del volumen nombrado
volumes:
  mongo-data:
Mejorado

Versión recomendada

docker-compose.yml
services:
  chanchito:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - monguito          # arranca después de mongo
    environment:
      - MONGO_URL=mongodb://${MONGO_USER}:${MONGO_PASSWORD}@monguito:27017/miapp?authSource=admin
    restart: unless-stopped

  monguito:
    image: mongo:7        # versión fija
    ports:
      - "27017:27017"     # opcional: solo si querés entrar con Compass
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
    volumes:
      - mongo-data:/data/db

volumes:
  mongo-data:
  • depends_on en vez de links
  • Credenciales en .env, no en el YAML (no se suben a git)
  • En app.js: mongoose.connect(process.env.MONGO_URL)
5

Compose de desarrollo

Monta tu carpeta en el contenedor: editás y nodemon recarga, sin rebuild.

docker-compose-dev.yml

docker-compose-dev.yml-f docker-compose-dev.yml up
services:
  chanchito:
    build:
      context: .                  # carpeta usada como contexto
      dockerfile: Dockerfile.dev  # Dockerfile a usar
    ports:
      - "3000:3000"
    links:
      - monguito
    volumes:
      - .:/home/app               # reemplaza al COPY del Dockerfile

  monguito:
    image: mongo
    ports:
      - "27017:27017"
    environment:
      - MONGO_INITDB_ROOT_USERNAME=mati
      - MONGO_INITDB_ROOT_PASSWORD=<password>
    volumes:
      - mongo-data:/data/db

volumes:
  mongo-data:

Cómo funciona el bind mount

Antes: COPY . /home/app (copia fija en la imagen). Ahora: .:/home/app (carpeta compartida en vivo).

Tu PC ./app.js editás y guardás Ctrl + S chanchito /home/app/app.js mismo archivo .:/home/app nodemon -L detecta el cambio app reiniciada ✓ sin docker build sin reiniciar compose
6

Producción vs Desarrollo

Las diferencias entre tus dos archivos, en una tabla.

Comparativa

ProducciónDesarrollo
Archivo composedocker-compose.ymldocker-compose-dev.yml
DockerfileDockerfile (build: .)Dockerfile.dev (context + dockerfile)
CódigoCopiado en la imagen con COPYMontado con volumes: - .:/home/app
Arranquenode app.jsnodemon -L app.js (recarga automática)
Al cambiar códigodocker compose up --buildNada: guardás y listo
Levantardocker compose updocker compose -f docker-compose-dev.yml up
7

Variables y archivo .env

Saca contraseñas del YAML. Compose lee automáticamente el .env de la misma carpeta.

1. Crear .env

.envagregalo al .gitignore
MONGO_USER=mati
MONGO_PASSWORD=<password>

2. Usarlas en el compose

environment:
  - MONGO_INITDB_ROOT_USERNAME=${MONGO_USER}
  - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
# o pasar el archivo entero al contenedor:
env_file: .env

3. Verificar

docker compose config
Muestra el YAML con las variables ya reemplazadas.
i

MONGO_INITDB_ROOT_* solo se aplica la primera vez (con el volumen vacío). Si cambiás la contraseña después, hacé down -v o cambiala dentro de Mongo.

8

Varios servicios: db · migrator · backend · frontend

El patrón de tu proyecto ASP.NET Core: el compose orquesta, cada Dockerfile solo construye.

Esqueleto

services:
  db:
    image: postgres:16
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 10

  migrator:
    build:
      context: ./aspnet-core          # TODA la solución
      dockerfile: src/<Proyecto>.DbMigrator/Dockerfile
    depends_on:
      db:
        condition: service_healthy    # espera a que la DB esté lista

  backend:
    build:
      context: ./aspnet-core
      dockerfile: src/<Proyecto>.HttpApi.Host/Dockerfile
    ports:
      - "44300:8080"                  # PC:44300 -> contenedor:8080
    environment:
      - ConnectionStrings__Default=Host=db;Database=app;Username=postgres;Password=${DB_PASSWORD}
    depends_on:
      migrator:
        condition: service_completed_successfully

  frontend:
    build: ./angular
    ports:
      - "4200:80"
    depends_on:
      - backend

volumes:
  pg-data:

Claves de este patrón

  • context = qué carpeta ve el Dockerfile. Si el proyecto depende de otros (Domain, Application…), el context tiene que ser la raíz de la solución.
  • dockerfile = ruta al Dockerfile relativa al context.
  • depends_on solo ordena el arranque. Para esperar a que algo esté listo usá condition: service_healthy + healthcheck.
  • service_completed_successfully: el backend arranca recién cuando el migrator terminó bien.
  • En .NET, __ (doble guion bajo) en una variable = : en appsettings.json (ConnectionStrings:Default).
  • El host de la DB en el connection string es el nombre del servicio (Host=db).
✓

Regla de oro: el Dockerfile no sabe de puertos externos, variables ni de otros contenedores. Todo eso vive en el compose.