Docker Compose - Multi-Container Stack

Docker Compose allows you to define and start complete stacks (app + database + cache + proxy) with a single YAML file.

02

Installation

bash
# Docker + Compose plugin (modern method, recommended)
sudo apt update
sudo apt install docker.io docker-compose-plugin -y

# Verify
docker compose version
# Note: the command is "docker compose" (with space), not "docker-compose"

If you already have Docker installed without the plugin:

bash
# Add Compose plugin manually
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 \
  -o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
03

Basic structure of a `docker-compose.yml`

yaml
services:
  app:
    image: node:20-alpine
    container_name: my-app
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
    depends_on:
      - db
    volumes:
      - ./app:/usr/src/app

  db:
    image: mysql:8.0
    container_name: my-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
      MYSQL_USER: dbuser
      MYSQL_PASSWORD: dbpass
    volumes:
      - db_data:/var/lib/mysql

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

volumes:
  db_data:
04

Essential commands

bash
# Start everything (in background)
docker compose up -d

# Start and rebuild images
docker compose up -d --build

# Stop everything
docker compose down

# Stop and remove volumes (WARNING: deletes data)
docker compose down -v

# See logs
docker compose logs -f
docker compose logs -f app     # only one service

# Container status
docker compose ps

# Run a command in a container
docker compose exec app bash
docker compose exec db mysql -u root -p

# Restart a single service
docker compose restart app

# Scale a service (multiple instances)
docker compose up -d --scale app=3
05

Example: WordPress + MySQL + Nginx

yaml
# docker-compose.yml
services:
  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - wordpress_data:/var/www/html
    depends_on:
      - wordpress

  wordpress:
    image: wordpress:php8.2-fpm-alpine
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppassword
    volumes:
      - wordpress_data:/var/www/html

  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppassword
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db_data:/var/lib/mysql

volumes:
  wordpress_data:
  db_data:
06

Example: Node.js + PostgreSQL + Redis

yaml
services:
  api:
    build: .
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file: .env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: redis-server --requirepass redispassword

volumes:
  pg_data:
07

Environment variables with `.env`

bash
# .env (same path as docker-compose.yml)
DB_PASSWORD=secure_password
APP_PORT=3000
yaml
# docker-compose.yml
services:
  app:
    environment:
      - DB_PASSWORD=${DB_PASSWORD}
      - APP_PORT=${APP_PORT}

Never commit .env file to Git. Add it to .gitignore.

08

Networking between containers

Containers from the same docker-compose.yml can communicate using the service name as hostname:

yaml
# The "app" service connects to the database using "db:5432"
environment:
  DB_HOST: db        # service name, not localhost!
  DB_PORT: 5432
09

Automatic startup on boot

With restart: unless-stopped or restart: always, containers automatically restart. Docker must be enabled as a service:

bash
sudo systemctl enable docker
10

Update containers

bash
# Download new images
docker compose pull

# Recreate containers with new images
docker compose up -d --pull always

# Clean up old images
docker image prune -f

DeluxHost, founded in 2023, offers high-quality hosting solutions for various digital needs. We provide shared hosting, VPS, and dedicated servers with advanced security and global data centers.

© DeluxHost, All rights reserved. | VAT Number : IT17734661006
All Systems Operational