BLOG // [DOCKER] Docker Compose for Beginners (v2) — Hands-on Practice
Docker Compose for Beginners (v2) — Hands-on Practice

Docker Compose for Beginners (v2) — Hands-on Practice

A guide to Docker Compose v2 from basics with best practices and real-world examples for beginners.

DOCKER

Docker Compose v2 - Multi-container Management Tool

Docker Compose is a tool that helps you define and run multiple containers simultaneously through a YAML file. Version v2 brings many improvements in performance and new features.


I. Installation and Preparation

Check Docker Compose Version

1
2
3
4
5
# Check current version
docker compose version

# Expected output (v2.x.x)
Docker Compose version v2.24.5

Basic Project Structure

1
2
3
4
5
6
7
8
my-app/
├── docker-compose.yml
├── .env
├── app/
│   ├── Dockerfile
│   └── src/
└── nginx/
    └── nginx.conf

II. Docker Compose v2 Syntax

Basic docker-compose.yml File

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
version: "3.8"

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - db

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

volumes:
  postgres_data:

Using .env File

1
2
3
4
5
6
7
# .env file
NODE_ENV=development
DB_HOST=db
DB_PORT=5432
DB_NAME=myapp
DB_USER=user
DB_PASSWORD=password
1
2
3
4
5
6
7
# docker-compose.yml
services:
  web:
    environment:
      - NODE_ENV=${NODE_ENV}
      - DB_HOST=${DB_HOST}
      - DB_PORT=${DB_PORT}

III. Best Practices for Docker Compose v2

Network Management

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: "3.8"

services:
  frontend:
    build: ./frontend
    networks:
      - frontend-network

  backend:
    build: ./backend
    networks:
      - frontend-network
      - backend-network

  database:
    image: postgres:15
    networks:
      - backend-network

networks:
  frontend-network:
    driver: bridge
  backend-network:
    driver: bridge

Health Checks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
services:
  web:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

Resource Limits

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
services:
  web:
    build: .
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M

IV. Common Docker Compose v2 Commands

Basic Commands

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Start services (detached mode)
docker compose up -d

# View logs
docker compose logs -f

# Stop services
docker compose down

# Rebuild and restart
docker compose up --build -d

# View service status
docker compose ps

Advanced Commands

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Run a command inside a container
docker compose exec web bash

# Scale a service
docker compose up --scale web=3 -d

# View resource usage
docker compose top

# Validate compose file
docker compose config

V. Real-World Example: Web App with Database

Node.js + PostgreSQL + Redis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

nginx.conf File

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
events {
    worker_connections 1024;
}

http {
    upstream app {
        server app:3000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://app;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

VI. Override and Multiple Environments

docker-compose.override.yml

1
2
3
4
5
6
7
8
9
# docker-compose.override.yml (automatically loaded)
version: "3.8"

services:
  app:
    volumes:
      - .:/app
    environment:
      - DEBUG=true

Environment-specific Files

1
2
3
4
5
# Development
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# docker-compose.prod.yml
version: "3.8"

services:
  app:
    restart: always
    deploy:
      resources:
        limits:
          memory: 1G
    environment:
      - NODE_ENV=production

Implementation Notes

  • When applying to your project, keep these important points in mind:
    • Always use .env files for sensitive data
    • Implement health checks for critical services
    • Use named volumes for persistent data
    • Configure appropriate restart policies
  • Best practices:
    • Separate networks for security
    • Use specific image tags instead of latest
    • Implement a proper logging strategy
  • Troubleshooting:
    • Use docker compose logs to debug
    • Check docker compose config before deploying
    • Monitor resource usage with docker compose top

Conclusion

Docker Compose v2 is a powerful tool that helps you manage multi-container applications with ease. With the best practices above, you can build and deploy applications professionally and efficiently!

Try experimenting with the examples above and gradually apply them to your real-world projects.

RESPONSES & DISCUSSION