Skip to content

Docker Compose

Define and run multiple containers as one app with a YAML file. One docker compose up starts your model API, database, and UI together — with shared networks, volumes, and env vars.

Table of Contents

Installation / Setup

docker compose version          # bundled with Docker Desktop / modern engine
# classic standalone:  pip install docker-compose  (older v1 — avoid)

Create compose.yaml (or docker-compose.yml) in the project root. All commands run from that directory.

Core Syntax

The file

services:              # each container = one service
  api:
    build: .           # build from local Dockerfile
    ports:
      - "8000:8000"
    environment:
      - DB_URL=postgresql://db:5432/mydb
    volumes:
      - ./app:/app     # bind mount for dev
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data   # named volume persists data

volumes:
  pgdata:              # declare named volumes

networks:              # (optional) custom networks

CLI

Command Does
docker compose up build + start (foreground)
docker compose up -d start detached
docker compose up --build rebuild images first
docker compose down stop + remove containers/network
docker compose down -v also delete named volumes (data!)
docker compose ps status
docker compose logs -f api follow one service's logs
docker compose exec api bash shell inside a service
docker compose build build images only
docker compose pull pull images only
docker compose restart api restart one service

Common Operations

Environment variables

services:
  api:
    environment:
      MODEL_PATH: /models/best.pt        # literal
      - DATASET=big                       # or list form
    env_file:
      - .env                              # load from a file (gitignored!)

Secrets and per-developer config belong in .env (add to .gitignore); compose substitutes ${VAR}:

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set in .env}

Healthchecks & dependencies

services:
  api:
    depends_on:
      db:
        condition: service_healthy     # wait for db to be ready
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 10

Practical Examples

1. Data-science dev stack: Jupyter + Postgres

services:
  jupyter:
    image: jupyter/datascience-notebook:latest
    ports: ["8888:8888"]
    volumes:
      - ./notebooks:/home/jovyan/work
    environment:
      JUPYTER_TOKEN: devtoken

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: analyst
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: analysis
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports: ["5432:5432"]

volumes:
  pgdata:
docker compose up -d        # jupyter at localhost:8888, postgres at 5432

2. Model API + vector store (RAG service)

services:
  api:
    build: ./api
    ports: ["8000:8000"]
    environment:
      EMBEDDING_MODEL: sentence-transformers/all-MiniLM-L6-v2
      QDRANT_URL: http://qdrant:6333
    depends_on:
      qdrant:
        condition: service_healthy

  qdrant:
    image: qdrant/qdrant:latest
    volumes:
      - qdrant_data:/qdrant/storage
    healthcheck:
      test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/localhost/6333"]
      interval: 10s
      retries: 5

3. Training job (one-shot)

services:
  train:
    build: .
    command: python train.py --epochs 50
    volumes:
      - ./artifacts:/app/artifacts
    environment:
      - WANDB_MODE=offline
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
docker compose run --rm train     # run once, clean up after

Common Patterns

# Reuse an image for multiple services with different commands
services:
  worker:
    image: myapp:latest
    command: celery -A app worker
  beat:
    image: myapp:latest
    command: celery -A app beat
# Profiles: optional services (dev tools) not started by default
services:
  mlflow:
    image: ghcr.io/mlflow/mlflow
    profiles: ["tools"]
    command: mlflow server --host 0.0.0.0
docker compose --profile tools up -d     # start mlflow only when wanted

Best Practices

  • Name the file compose.yaml (modern default) and run commands from its directory.
  • Use .env for secrets/config, never hardcode; gitignore it.
  • Persist state in named volumes — container FS is disposable.
  • Add healthchecks to databases and services you depend on.
  • depends_on with condition: service_healthy, not bare ordering.
  • Prefer build: . in dev, image: (pulled from registry) in prod.
  • Pin image tags; avoid latest for anything important.
  • Split dev/prod with overrides: docker compose -f compose.yaml -f compose.prod.yaml up -d.
  • Use profiles for optional tools instead of commenting services in/out.

Common Mistakes

Mistake Consequence Fix
Missing volumes: declaration for named volumes Compose error Declare under top-level volumes:
Secret in compose.yaml committed Leaked credentials ${VAR} + .env gitignored
depends_on only (no healthcheck) App starts before DB ready condition: service_healthy
down -v in production Wipes databases Know that -v deletes volumes
Editing .env but not restarting Stale env in running services docker compose up -d again (recreates)
Forgetting ports for host access Can't reach the service Map host:container in ports
Version field version: "3" Deprecated noise Omit the version field (modern compose)
Building every run Slow iteration docker compose up --build only when Dockerfile changed

Troubleshooting

Symptom Cause Fix
service "api" is unhealthy Healthcheck failing docker compose logs api; check test command
port is already allocated Host port taken Change mapping or stop the other app
Service restarts forever Crash loop docker compose logs <svc>; fix entrypoint
Can't resolve db hostname Different network All services share the default network — name it if custom
Config from .env not applied .env not in project dir / cached Run compose from that dir; docker compose config to verify
Volume data "missing" Wrong volume/path docker volume ls; docker compose down kept volumes?
GPU not visible No deploy resources / toolkit missing Add deploy.resources; install nvidia-container-toolkit

Official Documentation

Last Updated

2026-09-06 — Initial version.