Batch 4: Cloud Ansible AWS & Azure Docker & Podman Apache & NGINX ← Full TOC

← Docker Index

🎼 Docker Compose — docker-compose.yml — multi-container apps

Docker Compose orchestrates multi-container applications on a single host. Define all services, networks, and volumes in one YAML file. Use for development, testing, and simple production deployments.

📋 Reference

ItemSyntaxDescription
versionversion: '3.9'Compose file version (3.9 = latest)
servicesservices:Container definitions
imageimage: nginx:alpineUse existing image
buildbuild: . / build: {context:., dockerfile:Dockerfile}Build from Dockerfile
portsports: - '8080:80'Host:container port mapping
environmentenvironment: - NODE_ENV=productionSet environment variables
env_fileenv_file: .envLoad variables from file
volumesvolumes: - ./data:/app/dataBind mount or named volume
depends_ondepends_on: [db, redis]Start order dependency
depends_on conditiondepends_on: db: condition: service_healthyWait for health check to pass
healthchecktest: ['CMD','curl','-f','http://localhost/health']Container health check
restartrestart: unless-stopped / always / on-failureRestart policy
networksnetworks: - backendConnect to network
network driverdriver: bridge / overlay / hostNetwork type
named volumevolumes: mydata:Define named volume at top level
profilesprofiles: [tools]Only start with --profile tools
deploydeploy: replicas: 3 resources: limits:Swarm mode deployment config
commandcommand: python app.pyOverride default CMD
entrypointentrypoint: /docker-entrypoint.shOverride ENTRYPOINT
secretssecrets: - db_passwordUse Docker secrets (Swarm)
configsconfigs: - nginx_confUse Docker configs
extendextends: file: base.yml service: webExtend another service definition
updocker compose up -dStart all services detached
downdocker compose down -vStop and remove containers (and volumes with -v)
logsdocker compose logs -f serviceStream logs from service
execdocker compose exec web bashShell into running service
scaledocker compose up -d --scale web=3Run multiple instances

💡 Example

# docker-compose.yml — Full stack MyWebUniversity
services:

  # ── Web / CGI server ────────────────────────────────────────
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        ENVIRONMENT: production
    image: mywebuniversity/web:latest
    container_name: mywebuniversity_web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html:/var/www/React/prod:ro
      - ./cgi-bin:/usr/lib/cgi-bin:ro
      - ./ssl:/etc/ssl/mywebuniversity:ro
      - ./logs:/var/log/apache2
    environment:
      APACHE_RUN_USER:  www-data
      APACHE_RUN_GROUP: www-data
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost/health"]
      interval: 30s
      timeout:  10s
      retries:  3
      start_period: 15s
    networks:
      - frontend
      - backend

  # ── Database ────────────────────────────────────────────────
  db:
    image: postgres:16-alpine
    container_name: mywebuniversity_db
    environment:
      POSTGRES_DB:       mywebuniversity
      POSTGRES_USER:     ${DB_USER:-admin}
      POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./sql/init.sql:/docker-entrypoint-initdb.d/01_init.sql:ro
    ports:
      - "127.0.0.1:5432:5432"    # localhost only
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout:  5s
      retries:  5
    networks:
      - backend

  # ── Cache ───────────────────────────────────────────────────
  cache:
    image: redis:7-alpine
    container_name: mywebuniversity_cache
    command: >
      redis-server
      --maxmemory 256mb
      --maxmemory-policy allkeys-lru
      --requirepass ${REDIS_PASSWORD:-changeme}
      --save 900 1 --save 300 10
    volumes:
      - redis_data:/data
    restart: unless-stopped
    networks:
      - backend

  # ── Admin tools (only with --profile tools) ─────────────────
  pgadmin:
    image: dpage/pgadmin4:latest
    environment:
      PGADMIN_DEFAULT_EMAIL:    admin@mywebuniversity.com
      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin}
    ports:
      - "127.0.0.1:5050:80"
    depends_on: [db]
    profiles: [tools]
    networks:
      - backend

volumes:
  postgres_data:
  redis_data:

networks:
  frontend:
    name: mywebuniversity_frontend
  backend:
    name: mywebuniversity_backend
    internal: true    # no external access

# ── .env file (never commit!) ─────────────────────────────────
# DB_PASSWORD=supersecretpassword
# REDIS_PASSWORD=redispassword
# PGADMIN_PASSWORD=pgadminpassword

# ── Commands ──────────────────────────────────────────────────
# docker compose up -d                # start all services
# docker compose up -d --profile tools  # include pgadmin
# docker compose down                 # stop (keep volumes)
# docker compose down -v              # stop + delete volumes
# docker compose logs -f web          # stream web logs
# docker compose exec web bash        # shell into web
# docker compose ps                   # show status
# docker compose pull                 # update images
# docker compose build --no-cache     # rebuild images

← Dockerfile Best Practices  |  🏠 Index