Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Deploying Multi-Container Applications with Docker Compose

Tech 1

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

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.