HxHippy

Docker Compose Basics

Define and run multi-container applications with Docker Compose.

Last updated: 2025-01-15

Docker Compose Fundamentals

Docker Compose defines multi-container applications in a single YAML file.

Basic Structure

# docker-compose.yml
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"

  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production

  db:
    image: postgres:16-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: secret

volumes:
  db-data:

Essential Commands

# Start services
docker compose up
docker compose up -d          # Detached mode
docker compose up --build     # Rebuild images

# Stop services
docker compose down
docker compose down -v        # Remove volumes too

# View status
docker compose ps
docker compose logs
docker compose logs -f api    # Follow specific service

# Execute commands
docker compose exec api sh
docker compose exec db psql -U postgres

# Restart services
docker compose restart
docker compose restart api

Service Configuration

Image vs Build

services:
  # Use existing image
  nginx:
    image: nginx:alpine

  # Build from Dockerfile
  api:
    build: ./api

  # Build with options
  app:
    build:
      context: .
      dockerfile: Dockerfile.prod
      args:
        NODE_ENV: production

Port Mapping

services:
  web:
    ports:
      - "8080:80"           # HOST:CONTAINER
      - "443:443"
      - "127.0.0.1:3000:3000"  # Localhost only

Environment Variables

services:
  api:
    environment:
      - NODE_ENV=production
      - API_KEY=${API_KEY}    # From shell/env file

    # Or from file
    env_file:
      - .env
      - .env.local

Complete Examples

Web Application Stack

services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    depends_on:
      - api

  api:
    build: ./api
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgres://postgres:secret@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_PASSWORD: secret

volumes:
  postgres-data:

Development Environment

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app            # Bind mount for hot reload
      - /app/node_modules # Preserve node_modules
    command: npm run dev
    environment:
      - NODE_ENV=development

Named Volumes vs Bind Mounts

services:
  db:
    volumes:
      # Named volume (managed by Docker)
      - db-data:/var/lib/postgresql/data

  app:
    volumes:
      # Bind mount (host path)
      - ./src:/app/src
      # Read-only bind mount
      - ./config:/app/config:ro

volumes:
  db-data:   # Declare named volume

Service Dependencies

services:
  api:
    depends_on:
      - db
      - redis

  # With health checks
  api:
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

Command Reference

Command Description
up Create and start containers
down Stop and remove containers
ps List containers
logs View output from containers
exec Execute command in container
build Build or rebuild services
pull Pull service images
restart Restart services
beginner Docker Compose Updated 2025-01-15
  • docker compose
  • yaml
  • services
  • multi-container