Robin.te.Hofstee

Docker Compose Cheatsheet

Robin te Hofstee13 min readViews1
Docker Compose Cheatsheet

Complete Docker Compose reference guide covering services, volumes, networks, commands, and configurations. Everything you need for container orchestration.

Docker Compose Cheatsheet

Introduction

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services, networks, and volumes. Then, with a single command, you create and start all the services from your configuration.

Official Documentation:


Getting Started

Basic Example

Here's a simple docker-compose.yml file:

# docker-compose.yml
version: '3.8'
 
services:
  web:
    build:
      context: ./Path
      dockerfile: Dockerfile
    ports:
      - "5000:5000"
    volumes:
      - .:/code
  redis:
    image: redis

Version 1 to 2 Migration

Docker Compose is now integrated into the official Docker installation. The syntax change is simple:

  • V1: docker-compose ARG
  • V2: docker compose ARG (no hyphen)

The functionality has only improved with this change.


Essential Commands

Version and Configuration

# Check Docker Compose version
docker compose version
 
# Validate and view the compose file
docker compose config

Container Lifecycle

# Start services
docker compose start
 
# Stop services
docker compose stop
 
# Restart services
docker compose restart
 
# Run a one-time command
docker compose run web bash

Creating and Managing Services

# Create containers without starting them
docker compose create
 
# Attach to a running container
docker compose attach web
 
# Pause services
docker compose pause
 
# Unpause services
docker compose unpause

Up and Down

# Wait for services to be running|healthy
docker compose wait
 
# Create and start containers
docker compose up
 
# Create and start in detached mode
docker compose up -d
 
# Build images before starting
docker compose up --build
 
# Stop and remove containers, networks
docker compose down
 
# Stop and remove containers, networks, volumes
docker compose down -v

Monitoring and Logs

# List containers
docker compose ps
 
# Display running processes
docker compose top
 
# Stream container events
docker compose events
 
# View output from containers
docker compose logs
 
# Follow log output
docker compose logs -f
 
# Tail last 100 lines
docker compose logs --tail=100

Building and Images

# List images used by services
docker compose images
 
# Build or rebuild services
docker compose build
 
# Build without cache
docker compose build --no-cache
 
# Push service images
docker compose push
 
# Copy files/folders between service and local filesystem
docker compose cp web:/app/file.txt ./file.txt
 
# Execute command in running container
docker compose exec web bash

Configuration Reference

Building Services

Build from Dockerfile

web:
  build: .
  args:
    APP_HOME: app

Custom Dockerfile

web:
  build:
    context: ./dir
    dockerfile: Dockerfile.dev
    args:
      buildno: 1
      gitcommithash: cdc3b19

Build from Image

web:
  image: ubuntu
  # or specific version
  image: ubuntu:22.04
  image: tutum/influxdb
  image: example-registry:4000/postgresql
  image: a4bc65fd  # image ID

Ports

Port Mapping

services:
  web:
    ports:
      - "3000"              # Random host port to container 3000
      - "8000:80"           # Host 8000 to container 80
      - "127.0.0.1:8001:8001"  # Localhost only
      - "6060:6060/udp"     # UDP port

Expose Ports

services:
  web:
    # Expose ports to linked services (not to host)
    expose:
      - "3000"
      - "8000"

Commands

Override Default Command

services:
  web:
    # String format
    command: bundle exec thin -p 3000
    
    # Array format (recommended)
    command: [bundle, exec, thin, -p, 3000]

Override Entrypoint

services:
  web:
    # String format
    entrypoint: /app/start.sh
    
    # Array format
    entrypoint: [php, -d, vendor/bin/phpunit]

Environment Variables

Direct Definition

services:
  web:
    environment:
      RACK_ENV: development
      SHOW: 'true'
      SESSION_SECRET:
      
    # Alternative array syntax
    environment:
      - RACK_ENV=development
      - SHOW=true

From File

services:
  web:
    # Single file
    env_file: .env
    
    # Multiple files (later files override earlier)
    env_file:
      - .env
      - .env.development

Example .env file:

RACK_ENV=development
SECRET_KEY=mysecretkey
DATABASE_URL=postgresql://localhost/mydb

Dependencies

Links (Legacy)

services:
  web:
    # Makes the 'db' service available as hostname 'database'
    links:
      - db:database
      - redis

Depends On (Simple)

services:
  web:
    depends_on:
      - db
      - redis

Depends On (Advanced)

services:
  web:
    depends_on:
      db:
        condition: service_healthy
      db-init:
        condition: service_completed_successfully

Conditions:

  • service_started - Default, wait for service to start
  • service_healthy - Wait for healthcheck to pass
  • service_completed_successfully - Wait for run-once service to complete

Volumes

Volume Types

services:
  db:
    volumes:
      # Anonymous volume
      - /var/lib/mysql
      
      # Host path (bind mount)
      - ./cache:/tmp/cache
      
      # Named volume
      - datavolume:/var/lib/mysql
      
      # Read-only mount
      - ./code:/code:ro
 
# Define named volumes
volumes:
  datavolume:

Named Volume Configuration

services:
  db:
    volumes:
      - dbdata:/var/lib/postgresql/data
 
volumes:
  dbdata:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /data/db

Networking

Default Network

By default, Compose creates a single network for your app. Each container joins this network and can communicate with other containers.

Custom Networks

services:
  web:
    networks:
      - frontend
      - backend
  
  db:
    networks:
      - backend
 
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

External Network

networks:
  default:
    external:
      name: my-pre-existing-network

Network Aliases

services:
  web:
    networks:
      frontend:
        aliases:
          - webserver
          - www

Restart Policies

services:
  web:
    restart: "no"              # Never restart (default)
    restart: always            # Always restart
    restart: on-failure        # Restart on failure
    restart: unless-stopped    # Always restart unless explicitly stopped

Healthcheck

services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 1m30s
      timeout: 10s
      retries: 3
      start_period: 40s

Test Options:

  • ["CMD", "executable", "arg1"] - Execute command directly
  • ["CMD-SHELL", "command"] - Execute with shell
  • ["NONE"] - Disable healthcheck

Advanced Features

Labels

Add metadata to containers:

services:
  web:
    labels:
      com.example.description: "Accounting web app"
      com.example.department: "Finance"
      com.example.version: "1.0"

DNS Configuration

services:
  web:
    # Single DNS server
    dns: 8.8.8.8
    
    # Multiple DNS servers
    dns:
      - 8.8.8.8
      - 8.8.4.4
    
    # Custom DNS search domains
    dns_search:
      - dc1.example.com
      - dc2.example.com

Device Mapping

services:
  web:
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"
      - "/dev/sda:/dev/xvda:rwm"

Link to containers not managed by this docker-compose.yml:

services:
  web:
    external_links:
      - redis_1
      - project_db_1:mysql
      - project_db_1:postgresql

Extra Hosts

Add hostname mappings:

services:
  web:
    extra_hosts:
      - "somehost:192.168.1.100"
      - "otherhost:192.168.1.101"

User and Group

services:
  web:
    # Run as specific user
    user: root
    
    # Run as user:group
    user: 1000:1000
    
    # Run as named user
    user: www-data

Working Directory

services:
  web:
    working_dir: /app

Resource Limits

services:
  web:
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Logging

services:
  web:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Logging Drivers:

  • json-file - Default JSON logging
  • syslog - Syslog logging
  • journald - Journald logging
  • gelf - Graylog Extended Log Format
  • fluentd - Fluentd logging
  • awslogs - AWS CloudWatch Logs

Common Patterns

Multi-Stage Application

version: '3.8'
 
services:
  # Database
  db:
    image: postgres:15
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: dbuser
      POSTGRES_PASSWORD: dbpass
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dbuser"]
      interval: 10s
      timeout: 5s
      retries: 5
 
  # Cache
  redis:
    image: redis:alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
 
  # Backend API
  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://dbuser:dbpass@db/myapp
      REDIS_URL: redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      - ./api:/app
    command: python manage.py runserver 0.0.0.0:8000
 
  # Frontend
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      REACT_APP_API_URL: http://localhost:8000
    depends_on:
      - api
    volumes:
      - ./frontend:/app
      - /app/node_modules
    command: npm start
 
  # Nginx Reverse Proxy
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - api
      - frontend
 
volumes:
  postgres_data:
  redis_data:

Development with Hot Reload

version: '3.8'
 
services:
  app:
    build:
      context: .
      target: development
    volumes:
      # Mount source code
      - .:/app
      # Prevent overwriting node_modules
      - /app/node_modules
    environment:
      NODE_ENV: development
    ports:
      - "3000:3000"
    command: npm run dev

Database with Initialization

version: '3.8'
 
services:
  db:
    image: postgres:15
    volumes:
      - postgres_data:/var/lib/postgresql/data
      # Mount initialization scripts
      - ./init-scripts:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: dbuser
      POSTGRES_PASSWORD: dbpass
 
volumes:
  postgres_data:

Useful Commands

Development Workflow

# Start development environment
docker compose up -d
 
# View logs for specific service
docker compose logs -f web
 
# Rebuild after changes
docker compose up -d --build
 
# Run tests
docker compose run --rm web npm test
 
# Access database
docker compose exec db psql -U dbuser -d myapp
 
# Clean up everything
docker compose down -v --remove-orphans

Production Workflow

# Build production images
docker compose -f docker-compose.prod.yml build
 
# Start production environment
docker compose -f docker-compose.prod.yml up -d
 
# Scale a service
docker compose -f docker-compose.prod.yml up -d --scale web=3
 
# Update a service
docker compose -f docker-compose.prod.yml up -d --no-deps --build web

Debugging

# Inspect a service
docker compose ps web
 
# Check service configuration
docker compose config
 
# View container processes
docker compose top
 
# Execute command in container
docker compose exec web sh
 
# Copy files from container
docker compose cp web:/app/logs ./logs

Environment-Specific Configs

Base Configuration

# docker-compose.yml
version: '3.8'
 
services:
  web:
    image: myapp:latest
    environment:
      NODE_ENV: production

Development Override

# docker-compose.override.yml
version: '3.8'
 
services:
  web:
    build: .
    volumes:
      - .:/app
    environment:
      NODE_ENV: development
    command: npm run dev

Production Configuration

# docker-compose.prod.yml
version: '3.8'
 
services:
  web:
    image: myapp:${VERSION:-latest}
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

Usage:

# Development (uses docker-compose.yml + docker-compose.override.yml)
docker compose up
 
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Tips and Best Practices

1. Use Environment Variables

services:
  db:
    image: postgres:${POSTGRES_VERSION:-15}
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}

2. Optimize Build Context

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
      # Only include necessary files
      args:
        - BUILD_DATE
        - VERSION

3. Use Named Volumes for Data

volumes:
  database_data:
    name: my_app_database
    external: false

4. Health Checks for Dependencies

services:
  web:
    depends_on:
      db:
        condition: service_healthy

5. Resource Limits in Production

services:
  web:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

6. Secure Secrets Management

# Use Docker secrets (Swarm mode)
docker secret create db_password ./db_password.txt
services:
  db:
    secrets:
      - db_password
 
secrets:
  db_password:
    external: true

Troubleshooting

Common Issues

Port already in use:

# Find process using port
lsof -i :8000
# Kill process or change port mapping

Permission denied:

services:
  web:
    user: "${UID}:${GID}"

Containers can't communicate:

# Check network
docker network ls
docker network inspect myapp_default

Service won't start:

# Check logs
docker compose logs service_name
 
# Check configuration
docker compose config

Additional Resources


Happy Containerizing! 🐳

Share this post
Robin te Hofstee

Written by Robin te Hofstee

Technology enthusiast with a deep love for programming. Sharing practical guides on React, Next.js, Linux and self-hosting.

How Git Works

1

Git is a distributed version control system that allows multiple people to collaborate on a project while maintaining a complete history of all change