Docker for Backend & AI Engineers
Trang chủ / Module 5
🧩 Module 5 / 12 · 1 tuần

Docker Compose — Điều phối multi-container cho local dev

Định nghĩa toàn bộ stack nhiều service bằng 1 file YAML, depends_on/healthcheck, biến môi trường, profiles.

ComposeYAMLLocal Dev
📌 Vì sao module này quan trọng

Gõ tay hàng chục lệnh docker run/network/volume mỗi lần khởi động môi trường dev là không thực tế. Docker Compose là công cụ bạn sẽ dùng hàng ngày trong suốt các khoá học trước (đã xuất hiện ở Module 2 khoá AI Engineer, Module 2 khoá Databricks cho local Airflow/Spark) — module này hệ thống hoá lại đầy đủ.

🎯 Mục tiêu học tập

  • Viết file docker-compose.yml định nghĩa đầy đủ 1 stack nhiều service
  • Sử dụng đúng depends_on kết hợp healthcheck để đảm bảo thứ tự khởi động đúng
  • Quản lý biến môi trường và secret cho từng môi trường (dev/staging) bằng file .env
  • Sử dụng profiles để bật/tắt linh hoạt một số service tuỳ ngữ cảnh (ví dụ chỉ bật khi cần debug)

Cấu trúc file docker-compose.yml

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/appdb
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - .:/app

  db:
    image: postgres:16
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=appdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

1 lệnh duy nhất docker compose up tạo network, volume, và khởi động toàn bộ 3 service theo đúng thứ tự phụ thuộc — thay thế cho việc gõ tay nhiều lệnh docker run/network create/volume create riêng lẻ đã học ở Module 3-4.

depends_on kết hợp Healthcheck — tránh race condition

depends_on đơn thuần (không có condition) chỉ đảm bảo thứ tự khởi động container, không đảm bảo service bên trong đã sẵn sàng nhận kết nối — Postgres container có thể đã "chạy" (process khởi động) nhưng database bên trong chưa kịp init xong, khiến API service kết nối vào bị lỗi dù chạy sau. Healthcheck định nghĩa cách kiểm tra service thực sự sẵn sàng (không chỉ "process đang chạy"), và condition: service_healthy khiến Compose chờ đến khi healthcheck pass mới khởi động service phụ thuộc — giải quyết đúng race condition này.

Biến môi trường & .env cho nhiều môi trường

# .env (không commit vào git — thêm vào .gitignore)
POSTGRES_PASSWORD=secret_local_only
API_KEY=sk-xxxxx

# docker-compose.yml tự động đọc file .env cùng thư mục
services:
  api:
    environment:
      - API_KEY=${API_KEY}

Với nhiều môi trường (dev/staging), dùng nhiều file compose kết hợp (docker compose -f docker-compose.yml -f docker-compose.dev.yml up) — file override chỉ cần khai báo phần khác biệt so với file gốc, tránh trùng lặp cấu hình.

Profiles — bật/tắt Service linh hoạt

services:
  api:
    build: .
  db:
    image: postgres:16
  pgadmin:
    image: dpage/pgadmin4
    profiles: ["debug"]   # chỉ khởi động khi profile "debug" được bật
# Chạy bình thường — không có pgadmin
docker compose up

# Chạy kèm công cụ debug
docker compose --profile debug up

Hữu ích cho các công cụ chỉ cần lúc debug (pgAdmin, Redis Commander...) — không khởi động mặc định mỗi lần lên môi trường dev, giữ stack gọn nhẹ.

🏋️ Bài tập thực hành

Stack 3 service hoàn chỉnh

Viết docker-compose.yml cho stack: 1 API service (FastAPI hoặc Laravel — chọn theo Module 6/7), 1 PostgreSQL với healthcheck đúng cách, 1 Redis. Đảm bảo API chỉ khởi động sau khi Postgres healthy. Thêm 1 service pgAdmin với profile "debug", xác nhận nó không khởi động khi chạy docker compose up bình thường.

📚 Tài nguyên học tập

✅ Tự đánh giá hoàn thành

  • Viết được docker-compose.yml cho stack 3+ service từ đầu
  • Dùng đúng depends_on + healthcheck để tránh race condition lúc khởi động
  • Quản lý biến môi trường qua .env, không hard-code secret trong file compose
  • Sử dụng profiles để tách biệt service chính và công cụ hỗ trợ debug