DEV Community

Haripriya Veluchamy
Haripriya Veluchamy

Posted on

Docker Compose: Orchestrating Multi-Container Applications 🧩

After working with individual Docker containers for a while, I quickly realized that most real-world applications require multiple containers working together. Managing these with individual docker run commands became tedious and error-prone. That's where Docker Compose comes in - it's been a game-changer for my workflow.

What is Docker Compose? πŸ€”

Docker Compose is a tool for defining and running multi-container Docker applications. With a single YAML file and a few commands, you can configure all your application's services and spin up your entire stack with one command.

Why Use Docker Compose?

Before diving into the how, let me explain why I switched to Docker Compose:

  • Simplicity: Define your entire application stack in a single file
  • Reproducibility: Everyone on your team gets the exact same environment
  • Service coordination: Automatic networking between containers
  • Environment variables: Easy configuration management
  • One-command operations: Start, stop, and rebuild your entire application stack

Writing docker-compose.yml Files

The heart of Docker Compose is the docker-compose.yml file. Here's a basic example:

version: '3'
services:
  web:
    image: nginx
    ports:
      - "80:80"
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example
Enter fullscreen mode Exit fullscreen mode

Let's break down the structure:

Basic Structure

  • version: Specifies the Compose file format version
  • services: Defines the containers to be created
  • volumes: (Optional) Defines named volumes
  • networks: (Optional) Defines custom networks

Defining Services

Each service represents a container. You can configure:

services:
  web:
    image: nginx                 # Use an existing image
    # OR
    build: ./web                 # Build from a Dockerfile
    build:                       # More build options
      context: ./web
      dockerfile: Dockerfile.dev
    ports:
      - "8080:80"                # Port mapping
    environment:                 # Environment variables
      NODE_ENV: development
    env_file: .env               # Or use an env file
    volumes:                     # Mount volumes
      - ./web:/usr/share/nginx/html
    depends_on:                  # Service dependencies
      - api
    restart: always              # Restart policy
Enter fullscreen mode Exit fullscreen mode

Managing Application Stacks

A Complete Example: Web App with Database and Cache

Here's a more realistic example of an application stack I might use:

version: '3'

services:
  web:
    build: ./frontend
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - REACT_APP_API_URL=http://api:5000
    depends_on:
      - api

  api:
    build: ./backend
    ports:
      - "5000:5000"
    volumes:
      - ./backend:/app
      - /app/node_modules
    environment:
      - DB_HOST=db
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis

  db:
    image: postgres:13
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=secretpassword
      - POSTGRES_USER=myuser
      - POSTGRES_DB=myapp

  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

volumes:
  postgres-data:
  redis-data:
Enter fullscreen mode Exit fullscreen mode

This setup includes:

  • A React frontend
  • A backend API
  • A PostgreSQL database
  • A Redis cache
  • Persistent volumes for data
  • Environment configuration
  • Service dependencies

Environment Configuration

There are several ways to manage environment variables:

  1. Inline in the compose file:
services:
  web:
    environment:
      - NODE_ENV=development
      - API_URL=http://api:5000
Enter fullscreen mode Exit fullscreen mode
  1. From a .env file:
services:
  web:
    env_file:
      - ./web.env
Enter fullscreen mode Exit fullscreen mode
  1. From the shell environment:
services:
  web:
    environment:
      - NODE_ENV
      - API_KEY
Enter fullscreen mode Exit fullscreen mode

For sensitive data, I prefer using .env files that are git-ignored.

Compose Commands

Building and Running Services

These are the commands I use most often:

# Start all services
docker-compose up

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

# Build or rebuild services
docker-compose build

# Build and start
docker-compose up --build

# Stop services
docker-compose down

# Stop and remove volumes
docker-compose down -v
Enter fullscreen mode Exit fullscreen mode

Viewing Logs and Status

# View logs of all services
docker-compose logs

# Follow logs of a specific service
docker-compose logs -f web

# See running services
docker-compose ps
Enter fullscreen mode Exit fullscreen mode

Conclusion

Docker Compose has fundamentally changed how I develop and deploy multi-container applications. What used to take dozens of commands and careful coordination can now be defined in a single file and launched with one command.

The key benefits I've experienced:

  • Development environments that perfectly match production
  • Easy onboarding for new team members
  • Consistent deployments across environments
  • Simplified local development workflow

If you're working with Docker and managing more than one container, Compose should definitely be part of your toolkit.

In the next post, I'll discuss how to move your Docker Compose setups towards production-ready deployments.


Next up: "Docker in Production: From Development to Deployment"

Top comments (0)