Docker Compose
01 / 02

Services, Networking, Volumes & Ports

Services, Networking, Volumes & Ports

A Basic docker-compose.yml

services:
  web:
    build: .
    ports:
      - "8080:80"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      db:
        condition: service_healthy

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

volumes:
  db_data:

Dockerfile builds one image; docker-compose.yml runs one or more services together. image uses a pre-built image (postgres:16); build compiles from a local Dockerfile — a typical app mixes both. Services reach each other by service name (web connects to "db") thanks to automatic Compose networking — no manual IP wiring.

Ports vs. Internal Networking

ports: "8080:80" maps HOST:CONTAINER — needed to reach a service from outside Docker (a browser on the host). Internal service-to-service calls (web -> db) don't need a ports mapping at all, just the shared Compose network.

Volumes: Named vs. Bind Mount

A named volume (db_data above) is Docker-managed, ideal for persistent data like a database's files, surviving container recreation. A bind mount maps an explicit host path into the container — common for live-syncing local source code during development.

.env Substitution

${DB_PASSWORD} pulls from a .env file (often git-ignored) — keeps secrets out of the committed compose file while the file itself stays safely checked into version control.

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free