Docker Compose for Development

Learn how to use Docker Compose to create and manage multi-container development environments

Docker Compose for Development

Learn How to Use Docker Compose to Create and Manage Multi-Container Development Environments

Quick Navigation

Difficulty: 🟢 Beginner
Estimated Time: 15-25 minutes
Prerequisites: Basic Docker knowledge, Understanding of containers, Command line experience

What You'll Learn

This tutorial covers essential Docker Compose concepts and tools:

  • Docker Compose Basics - Understanding compose files and services
  • Development Workflows - Setting up local development environments
  • Service Orchestration - Managing multiple containers together
  • Environment Management - Different configurations for dev, test, and prod
  • Development Tools - VS Code integration and development scripts
  • Best Practices - Service organization and performance optimization

Prerequisites

  • Basic Docker knowledge and container concepts
  • Understanding of multi-container applications
  • Command line experience with Docker commands

Introduction

Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file to configure your application's services, networks, and volumes, making it perfect for development environments where you need multiple services working together.

Why Use Docker Compose for Development?

  • Consistent environments - Same setup across team members
  • Easy service management - Start/stop all services with one command
  • Service dependencies - Automatic startup order management
  • Environment isolation - Separate dev, test, and production configs
  • Quick iteration - Fast rebuilds and restarts

Step-by-Step Instructions

Step 1: Install Docker Compose

Docker Compose comes pre-installed with Docker Desktop. For Linux users:

# Install Docker Compose plugin
sudo apt-get update
sudo apt-get install docker-compose-plugin

# Verify installation
docker compose version

Step 2: Create Your First Compose File

Create a new directory and compose file:

mkdir docker-compose-demo
cd docker-compose-demo
touch docker-compose.yml

Step 3: Basic Compose File Structure

version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

Step 4: Run Your Services

# Start all services
docker compose up

# Start in background
docker compose up -d

# View logs
docker compose logs

# View logs for specific service
docker compose logs web

Step 5: Development Workflow

# Stop services
docker compose down

# Rebuild and start
docker compose up --build

# View running services
docker compose ps

# Execute commands in running containers
docker compose exec web sh
docker compose exec db psql -U user -d myapp

Advanced Development Setup

Full-Stack Development Environment

version: '3.8'

services:
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - REACT_APP_API_URL=http://localhost:8000
    depends_on:
      - backend

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - DEBUG=True
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:

Development with Hot Reloading

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true
    command: npm run dev

Environment-Specific Configurations

Development Configuration (docker-compose.yml)

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development
      - DEBUG=true
    command: npm run dev

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp_dev
      POSTGRES_USER: dev_user
      POSTGRES_PASSWORD: dev_password
    ports:
      - "5432:5432"

Production Configuration (docker-compose.prod.yml)

version: '3.8'

services:
  app:
    build: .
    ports:
      - "80:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  postgres_data:

Using Environment Files

Create .env file:

# .env
NODE_ENV=development
DATABASE_URL=postgresql://user:password@db:5432/myapp
POSTGRES_DB=myapp_dev
POSTGRES_USER=dev_user
POSTGRES_PASSWORD=dev_password

Reference in compose file:

version: '3.8'

services:
  app:
    build: .
    environment:
      - NODE_ENV=${NODE_ENV}
      - DATABASE_URL=${DATABASE_URL}
    env_file:
      - .env

Development Tools and Extensions

VS Code Integration

Install the "Docker" extension and add to .vscode/settings.json:

{
  "docker.composeFile": "docker-compose.yml",
  "docker.defaultComposeFile": "docker-compose.yml"
}

Development Scripts

Add to package.json:

{
  "scripts": {
    "dev:up": "docker compose up -d",
    "dev:down": "docker compose down",
    "dev:logs": "docker compose logs -f",
    "dev:rebuild": "docker compose up --build -d",
    "dev:clean": "docker compose down -v --remove-orphans"
  }
}

Troubleshooting

Common Issues and Solutions

Issue: Port already in use

# Solution: Check what's using the port
lsof -i :3000

# Or use different ports
ports:
  - "3001:3000"

Issue: Services not starting in correct order

# Solution: Use depends_on with health checks
depends_on:
  db:
    condition: service_healthy

Issue: Volume mounts not working

# Solution: Check file permissions and paths
volumes:
  - ./app:/app:delegated

Debugging Tips

# Check service status
docker compose ps

# View service logs
docker compose logs -f service_name

# Inspect running containers
docker compose exec service_name sh

# Check network connectivity
docker compose exec service_name ping other_service

Best Practices

Service Organization

  • Group related services together
  • Use descriptive service names
  • Keep services focused and single-purpose

Environment Management

  • Use .env files for configuration
  • Separate dev, test, and prod configs
  • Never commit sensitive data

Development Workflow

  • Use volume mounts for code changes
  • Implement health checks for dependencies
  • Use restart policies appropriately

Performance Optimization

  • Use named volumes for persistent data
  • Implement proper cleanup procedures
  • Monitor resource usage

Next Steps

Additional Resources

Conclusion

Docker Compose is an essential tool for modern development workflows. It helps you create consistent development environments, manage multiple services easily, speed up development iteration, ensure team consistency, and simplify deployment processes.

Key Takeaways

  • Multi-Container Management - Orchestrate complex development environments
  • Environment Consistency - Same setup across team members and machines
  • Rapid Development - Fast rebuilds and service restarts
  • Service Dependencies - Automatic startup order and health checks
  • Configuration Management - Environment-specific settings and secrets

Next Steps

  1. Set up your first multi-container environment using the examples provided
  2. Customize configurations for your specific development needs
  3. Integrate with your IDE for seamless development experience
  4. Explore advanced features like health checks and service discovery
  5. Implement best practices for production-ready configurations

Start using Docker Compose in your development workflow today and experience faster, more reliable development!


Tags: #Docker #DockerCompose #Development #MultiContainer #Orchestration #DevOps #Containerization