Featured image of post 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 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

1. 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

2. 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

1. 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:

2. 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

1. 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

2. 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

3. 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

1. 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

2. 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

1. 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:

2. 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

1. 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

2. 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. 😊