DevToolBoxGRATIS
Blogg

Docker Compose Jukseark: Tjenester, Volumer og Nettverk

10 min lesningby DevToolBox

Docker Compose lets you define and run multi-container applications with a single YAML file. This cheat sheet covers everything from basic service definitions to production-ready stack configurations.

File Structure

A docker-compose.yml file consists of four main sections:

# docker-compose.yml
services:      # Container definitions
  web:
    image: nginx:alpine
  api:
    build: ./api

volumes:       # Persistent storage
  db-data:

networks:      # Custom networks
  frontend:
  backend:

Service Configuration

Image vs Build

services:
  # Use a pre-built image
  db:
    image: postgres:16

  # Build from Dockerfile
  api:
    build: ./api

  # Build with custom options
  web:
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod
      args:
        NODE_ENV: production

Port Mapping

services:
  web:
    ports:
      - "80:80"         # host:container
      - "443:443"
      - "3000:3000"     # Expose to localhost
      - "127.0.0.1:8080:80"  # Bind to specific interface

Environment Variables

services:
  api:
    # Inline environment variables
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_PORT=5432

    # From external file
    env_file:
      - .env
      - .env.production

Restart Policies

services:
  web:
    restart: "no"             # Default: never restart
  api:
    restart: always           # Always restart
  db:
    restart: unless-stopped   # Restart unless manually stopped
  worker:
    restart: on-failure       # Restart only on failure
    # restart: on-failure:5   # Max 5 retries

Health Checks

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

Volumes

services:
  db:
    volumes:
      # Bind mount (host path : container path)
      - ./data:/var/lib/postgresql/data

      # Named volume
      - db-data:/var/lib/postgresql/data

      # Read-only mount
      - ./config:/etc/app/config:ro

volumes:
  db-data:           # Named volume declaration
    driver: local

Networks

services:
  web:
    networks:
      - frontend
  api:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true    # No external access

Complete Stack Examples

Node.js + MongoDB + Redis

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - MONGO_URL=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis

  mongo:
    image: mongo:7
    volumes:
      - mongo-data:/data/db
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  mongo-data:

Django + PostgreSQL

services:
  web:
    build: .
    command: gunicorn myapp.wsgi:application --bind 0.0.0.0:8000
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgres://postgres:secret@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - static:/app/static

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_PASSWORD: secret
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  pg-data:
  static:

WordPress + MySQL + phpMyAdmin

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: wp_pass
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp-content:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:8
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: wp_pass
      MYSQL_ROOT_PASSWORD: root_secret
    volumes:
      - db-data:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin:latest
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db

volumes:
  wp-content:
  db-data:

Essential CLI Commands

CommandDescription
docker compose up -dStart services in background
docker compose downStop and remove containers
docker compose down -vStop and remove containers + volumes
docker compose logs -fFollow service logs
docker compose logs apiLogs for specific service
docker compose psList running containers
docker compose exec api shShell into running container
docker compose buildBuild/rebuild images
docker compose pullPull latest images
docker compose restart apiRestart specific service
docker compose configValidate and view config
docker compose topShow running processes

Environment Files (.env)

Docker Compose automatically reads a .env file in the same directory:

# .env file
POSTGRES_VERSION=16
POSTGRES_PASSWORD=my_secret_pass
APP_PORT=3000

# docker-compose.yml
services:
  db:
    image: postgres:${POSTGRES_VERSION}
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
  app:
    ports:
      - "${APP_PORT}:3000"

Common Mistakes

MistakeFix
Using `latest` tag in productionPin specific version tags (e.g., `postgres:16.1`)
Storing secrets in docker-compose.ymlUse .env files or Docker secrets
Not using named volumes for dataNamed volumes persist across `docker compose down`
Missing restart policyAdd `restart: unless-stopped` for production services
Not setting resource limitsUse `deploy.resources.limits` for memory/CPU

FAQ

What is the difference between docker-compose and docker compose?

docker-compose (with hyphen) is the legacy Python-based tool (V1). docker compose (space, no hyphen) is the new Go-based plugin (V2) integrated into Docker CLI. Docker Compose V2 is now the default and recommended version.

How do I persist data in Docker Compose?

Use named volumes for database data and other persistent storage. Named volumes survive docker compose down. Bind mounts map host directories directly and are useful for development.

How do containers communicate in Docker Compose?

All services in a docker-compose.yml share a default network. Services can reach each other using the service name as hostname (e.g., `db:5432` from the app service to the database service).

Can I use Docker Compose in production?

Yes, but for larger deployments consider Docker Swarm or Kubernetes. Docker Compose is great for single-host deployments, development environments, and CI/CD pipelines.

𝕏 Twitterin LinkedIn
Var dette nyttig?

Hold deg oppdatert

Få ukentlige dev-tips og nye verktøy.

Ingen spam. Avslutt når som helst.

Try These Related Tools

🐳Docker Compose GeneratorYMLYAML Validator & FormatterY{}JSON ↔ YAML Converter

Related Articles

Nginx Config Eksempler: Reverse Proxy, SSL og Statiske Sider

Produksjonsklare Nginx-konfigurasjoner: reverse proxy, SSL/TLS, statiske filer, lastbalansering.

Docker Compose YAML-validering: 10 Vanlige Syntaksfeil og Hvordan Fikse dem

Slutt å kaste bort tid på Docker Compose YAML-feil. Lær å identifisere og fikse de 10 vanligste feilene.

Docker Compose Generator -- Build docker-compose.yml Online

Complete guide to generating docker-compose.yml files online. Learn Docker Compose file structure, services, networks, volumes, environment variables, health checks, depends_on, profiles, override files, common patterns, and production best practices.