Deploying Multi-Container Applications with Docker Compose
Introduction to Docker Compose
Docker Compose is a tool designed for defining and running applications that require multiple Docker containers. Instead of managing each container individually through the CLI, you describe your entire application stack in a configuration file.
With a docker-compose.yml (or compose.yaml) file, you can:
- Define services such as web servers, databases, and caching layers using code
- Configure inter-service dependencies, networking, and persistent storage volumes
- Start or stop the entire application stack with a single command like
docker compose up
Compose V2 Notes
Modern Docker Desktop versions (v2.0 and above) integrate Compose functionality directly into the Docker CLI as a subcommand. This version is called Compose V2 and functions as a Docker plugin. The syntax remains nearly identical, though command usage differs slightly.
| Context | Command Format |
|---|---|
| Legacy versions | docker-compose |
| V2 (current) | docker compose |
| Documentation/genarel | Docker Compose |
Installing Docker Compose
Verify the installation by checking the version:
docker compose version
If Docker Compose is not installed, install it using your package manager. For RHEL-based distributions:
sudo yum install -y docker-compose-plugin
Creating the docker-compose.yml File
The filename should be consistent and placed at the project root. Below is a comprehensive example that defines a typical web application stack with a database, cache, application server, and reverse proxy.
version: '3.8'
services:
postgres:
image: postgres:15
container_name: postgres-db
ports:
- "5432:5432"
environment:
TZ: America/New_York
POSTGRES_USER: admin
POSTGRES_PASSWORD: secure_password_123
POSTGRES_DB: appdb
volumes:
- "/data/app/postgres/postgresql.conf:/etc/postgresql/postgresql.conf"
- "/data/app/postgres/wal:/var/lib/postgresql/wal"
- "/data/app/postgres/storage:/var/lib/postgresql/data"
networks:
- app-network
restart: unless-stopped
cache:
image: redis:7.0
container_name: redis-cache
ports:
- "6380:6379"
environment:
TZ: America/New_York
volumes:
- "/data/app/redis/redis.conf:/usr/local/etc/redis/redis.conf"
- "/data/app/redis/persistence:/data"
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
networks:
- app-network
restart: unless-stopped
api-server:
build:
context: ./backend
dockerfile: Dockerfile
image: api-service:latest
container_name: api-container
ports:
- "3000:3000"
environment:
TZ: America/New_York
DB_HOST: postgres
REDIS_HOST: cache
volumes:
- "/data/app/backend/uploads:/app/uploads"
- "/data/app/backend/logs:/var/log/app"
networks:
- app-network
depends_on:
- postgres
- cache
restart: unless-stopped
user: "1001:1001"
reverse-proxy:
image: nginx:1.25
container_name: nginx-proxy
ports:
- "80:80"
- "8443:443"
volumes:
- "/data/app/nginx/html:/usr/share/nginx/html"
- "/data/app/nginx/access.log:/var/log/nginx/access.log"
- "/data/app/nginx/error.log:/var/log/nginx/error.log"
- "/data/app/nginx/ssl:/etc/nginx/ssl:ro"
- "/data/app/nginx/nginx.conf:/etc/nginx/nginx.conf"
- "/data/app/nginx/conf.d:/etc/nginx/conf.d:ro"
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "10"
tag: "{{.Name}}/{{.ID}}"
networks:
- app-network
depends_on:
- api-server
restart: unless-stopped
networks:
app-network:
name: application-net
driver: bridge
Configuration Breakdown
Each service definition includes several key sections:
postgres:
image: postgres:15
container_name: postgres-db
ports:
- "5432:5432"
environment:
TZ: America/New_York
POSTGRES_USER: admin
POSTGRES_PASSWORD: secure_password_123
POSTGRES_DB: appdb
volumes:
- "/data/app/postgres/postgresql.conf:/etc/postgresql/postgresql.conf"
- "/data/app/postgres/storage:/var/lib/postgresql/data"
networks:
- app-network
restart: unless-stopped
- image: Specifies the base image to use
- container_name: Assigns a custom name to the container
- ports: Maps host ports to container ports (host:container)
- environment: Sets environment variables for configuration
- volumes: Mounts host directories or files into the container
- networks: Assigns the container to specific networks
- restart: Defines the restart policy (always, unless-stopped, on-failure)
Managing Services
Starting the Stack
docker compose up -d --build
Flags explained:
up— Creates and starts all defined services-d— Runs containers in detached mode (background)--build— Builds images before starting containers (omit if using pre-built images)
Note: Commands must be executed from the directory containing the compose file.
Stopping the Stack
docker compose down
Project Structure Example
project/
├── docker-compose.yml
├── backend/
│ ├── Dockerfile
│ └── src/
├── postgres/
├── nginx/
│ ├── conf.d/
│ └── ssl/
└── redis/
Common Operations
List running containers:
docker compose ps
View logs:
# All services
docker compose logs
# Specific service
docker compose logs api-server
# Real-time tail
docker compose logs -f reverse-proxy
Restart individual services:
docker compose restart nginx-proxy
Recreate containers without cache:
docker compose up -d --build --force-recreate