Docker

Lesson 10

Compose services, volumes, and networks

Use Compose to define service boundaries, persistent volumes, and internal networks without overexposing ports or state.

Good Code

compose.yaml
services:
  app:
    build: .
    environment:
      DATABASE_HOST: db
    depends_on:
      db:
        condition: service_healthy
    # Only expose the web port the host needs.
    ports:
      - "3000:3000"
    networks:
      - internal

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: reviews
      POSTGRES_USER: reviews
    # Named volumes keep database data after container restarts.
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U reviews"]
      interval: 10s
      timeout: 5s
      retries: 5
    # Services talk to each other on a private network.
    networks:
      - internal

volumes:
  postgres_data:

networks:
  internal:

Bad Code

compose.yaml
services:
  app:
    build: .
    # Host networking removes the boundary between container and host.
    network_mode: host
    volumes:
      - .:/app
      # Mounting / exposes the host filesystem to the container.
      - /:/host

  db:
    image: postgres:latest
    # Opening the database port is often unnecessary for app-only access.
    ports:
      - "5432:5432"

Review Notes

What to review

Good Code

The good version names persistence, keeps services on an internal network, and exposes only the application port needed by the host.

Bad Code

The bad version uses host networking, mounts the host filesystem, and exposes the database without a clear reason.

Takeaways

  • A Compose file should make service relationships explicit while keeping persistence and exposure deliberate.