Compose Config and Usage

Back

Loading concept...

Docker Compose - The Orchestra Conductor 🎼

Imagine you’re running a restaurant. You don’t just have a chef—you have a chef, a waiter, a dishwasher, and a host. They all need to work together, start in the right order, and know how to recover when things go wrong.

Docker Compose is like the restaurant manager who coordinates everyone. One command, and the whole team springs into action!


🌍 Environment Configuration

What’s an Environment?

Think of environments like different “modes” for your app:

  • Development = Practice mode (okay to make mistakes)
  • Production = Show time (everything must be perfect)

Setting Up Environment Variables

Method 1: Inline in docker-compose.yml

services:
  web:
    image: myapp
    environment:
      - DATABASE_URL=postgres://db:5432
      - DEBUG=true

Method 2: Using an .env file Create a file called .env:

DATABASE_URL=postgres://db:5432
DEBUG=true
SECRET_KEY=my-super-secret

Then reference it:

services:
  web:
    image: myapp
    env_file:
      - .env

Why use .env files?

  • Keep secrets out of your code
  • Easy to change settings without editing the main file
  • Different .env files for different environments

🔗 depends_on and healthcheck

The “Wait for Me!” Problem

Imagine your web app needs the database. But what if the database isn’t ready yet?

graph TD A["Web App Starts"] --> B{Database Ready?} B -->|No| C["❌ App Crashes"] B -->|Yes| D["✅ App Works"]

depends_on: Basic Waiting

services:
  web:
    image: myapp
    depends_on:
      - db

  db:
    image: postgres

But wait! depends_on only waits for the container to start, not for it to be ready.

healthcheck: Smart Waiting

A healthcheck is like asking “Are you actually ready to work?”

services:
  db:
    image: postgres
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 5s
      timeout: 3s
      retries: 5

What this means:

  • Every 5 seconds, ask “Are you ready?”
  • Wait up to 3 seconds for an answer
  • Try 5 times before giving up

Combining Both Powers

services:
  web:
    depends_on:
      db:
        condition: service_healthy

  db:
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 5s
      timeout: 3s
      retries: 5

Now the web app waits until the database is truly ready!


🔄 Restart and Deploy Policies

Restart: What Happens When Things Crash?

Your app might crash. It happens! Restart policies decide what to do next.

services:
  web:
    image: myapp
    restart: always

Restart Options:

Policy What It Does
no Never restart (default)
always Always restart, no matter what
on-failure Only restart if it crashed
unless-stopped Restart unless you stopped it manually

Deploy: Production-Grade Settings

For serious production use, the deploy section gives you superpowers:

services:
  web:
    image: myapp
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

Translation:

  • Run 3 copies of this service
  • If one fails, wait 5 seconds, then try again
  • Give up after 3 attempts
  • Each copy gets max half a CPU and 512MB RAM

🎭 Compose Profiles

Why Profiles?

Sometimes you want different services for different situations:

  • Development: Include debugging tools
  • Production: Only essential services
  • Testing: Include test database

Creating Profiles

services:
  web:
    image: myapp
    # No profile = always runs

  db:
    image: postgres
    # No profile = always runs

  debug-tools:
    image: debug-toolkit
    profiles:
      - debug

  test-db:
    image: postgres
    profiles:
      - testing

Using Profiles

# Normal start (web + db only)
docker compose up

# Include debug tools
docker compose --profile debug up

# Include testing services
docker compose --profile testing up

# Multiple profiles
docker compose --profile debug --profile testing up

Think of profiles like “expansion packs” you can add when needed!


🛠️ Docker Compose Commands

The Essential Commands

graph TD A["docker compose up"] --> B["Start Everything"] C["docker compose down"] --> D["Stop & Remove"] E["docker compose ps"] --> F["List Running"] G["docker compose logs"] --> H["See Output"]

Quick Reference

Starting:

# Start all services
docker compose up

# Start in background (detached)
docker compose up -d

# Start specific services
docker compose up web db

Stopping:

# Stop everything
docker compose down

# Stop and remove volumes too
docker compose down -v

Monitoring:

# See what's running
docker compose ps

# View logs
docker compose logs

# Follow logs live
docker compose logs -f

# Logs for one service
docker compose logs web

Rebuilding:

# Rebuild and start
docker compose up --build

# Just rebuild
docker compose build

📁 Override Files

The Magic of Overrides

Imagine you have a base recipe, but want to add extra spices for different occasions.

Base file: docker-compose.yml

services:
  web:
    image: myapp
    ports:
      - "3000:3000"

Override file: docker-compose.override.yml

services:
  web:
    environment:
      - DEBUG=true
    volumes:
      - ./src:/app/src

Docker Compose automatically merges them!

Override Loading Order

graph TD A["docker-compose.yml"] --> B["Base Config"] B --> C["docker-compose.override.yml"] C --> D["Final Merged Config"]

Custom Override Files

# Use a specific override file
docker compose -f docker-compose.yml \
               -f docker-compose.prod.yml up

Common pattern:

  • docker-compose.yml → Base config
  • docker-compose.override.yml → Development extras
  • docker-compose.prod.yml → Production settings
  • docker-compose.test.yml → Testing settings

🔀 Variable Substitution

Making Your Compose Files Dynamic

Instead of hardcoding values, use variables!

In your .env file:

APP_PORT=3000
APP_VERSION=2.1.0
DB_PASSWORD=supersecret

In docker-compose.yml:

services:
  web:
    image: myapp:${APP_VERSION}
    ports:
      - "${APP_PORT}:3000"

  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}

Default Values

What if a variable isn’t set? Use defaults!

services:
  web:
    # Use 8080 if APP_PORT isn't set
    ports:
      - "${APP_PORT:-8080}:3000"

    # Require this variable (error if missing)
    environment:
      - SECRET_KEY=${SECRET_KEY:?Secret key required!}

Variable Substitution Syntax

Syntax Meaning
${VAR} Use the value of VAR
${VAR:-default} Use default if VAR is unset
${VAR:?error} Show error if VAR is unset
${VAR:+replacement} Use replacement if VAR is set

🎯 Putting It All Together

Here’s a complete example using everything we learned:

# docker-compose.yml
services:
  web:
    image: myapp:${APP_VERSION:-latest}
    ports:
      - "${WEB_PORT:-3000}:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/${DB_NAME}
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:15
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME:-myapp}
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
    volumes:
      - db-data:/var/lib/postgresql/data

  redis:
    image: redis:alpine
    profiles:
      - cache

volumes:
  db-data:

What this does:

  1. ✅ Web app waits for healthy database
  2. ✅ Uses environment variables for flexibility
  3. ✅ Has sensible defaults
  4. ✅ Redis only starts when needed (profile)
  5. ✅ Database data persists in a volume
  6. ✅ Auto-restarts on crash

🏆 Key Takeaways

  1. Environment Configuration → Use .env files to keep secrets safe
  2. depends_on + healthcheck → Make services wait properly
  3. restart + deploy → Handle failures gracefully
  4. Profiles → Add optional services when needed
  5. Commands → up, down, ps, logs are your daily tools
  6. Override files → Layer configs for different environments
  7. Variable substitution → Make configs flexible and reusable

You’re now ready to orchestrate containers like a pro! 🎼🐳

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.