
Docker Compose là công cụ định nghĩa và chạy multi-container Docker applications. Thay vì nhớ dài dòng docker run flags, bạn viết YAML file docker-compose.yml một lần, rồi docker compose up khởi động toàn bộ stack. Đây là cách chuẩn để cài đặt môi trường dev nhất quán trên macOS, Windows hay Linux.

Docker Compose là gì? Tại sao dùng?
Docker Compose giải quyết bài toán “nhưng nó chạy được trên máy tôi mà?”. Mỗi thành viên trong team có thể khởi động cùng một stack services (database, cache, backend, frontend) bằng một lệnh duy nhất:
docker compose up -d
Lợi ích cốt lõi:
- Reproducible: cùng một docker-compose.yml, cùng một môi trường trên mọi máy.
- Isolation: services chạy trong network riêng, không can thiệp local processes.
- Hot reload: mount volume code vào container, sửa file local → container reload ngay.
- One command teardown:
docker compose downxóa sạch network + container + volume (optional).
File docker-compose.yml tối thiểu
Ví dụ stack web app cơ bản: Node.js + PostgreSQL + Redis + Nginx.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
redis:
image: redis:7-alpine
restart: unless-stopped
ports:
- "127.0.0.1:6379:6379"
volumes:
- redisdata:/data
backend:
build: ./backend
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
environment:
DATABASE_URL: postgres://app:secret@db:5432/appdb
REDIS_URL: redis://redis:6379
volumes:
- ./backend/src:/app/src
ports:
- "127.0.0.1:3000:3000"
frontend:
build: ./frontend
restart: unless-stopped
depends_on:
- backend
volumes:
- ./frontend/src:/app/src
ports:
- "127.0.0.1:5173:5173"
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- frontend
- backend
volumes:
pgdata:
redisdata:

Các patterns thực tế
Health Checks
Database cần thời gian khởi động. depends_on chỉ chờ container start, không chờ service sẵn sàng. Giải pháp: health check.
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 2s
retries: 5
depends_on:
db:
condition: service_healthy
Build Arguments và Environment
Dùng .env file để quản lý secrets không commit lên git:
# .env (đưa vào .gitignore)
POSTGRES_USER=app
POSTGRES_PASSWORD=secret_from_env
BACKEND_PORT=3000
Trong docker-compose.yml:
services:
backend:
build:
context: ./backend
args:
NODE_ENV: ${NODE_ENV:-development}
env_file:
- .env
Volume Mounting cho Hot Reload
Mount source code vào container, kết hợp với nodemon/watch trong container để auto-restart khi file thay đổi:
backend:
build: ./backend
volumes:
- ./backend/src:/app/src
- /app/node_modules # anonymous volume, tránh ghi đè container node_modules
command: npm run dev
Override File cho Production
Dùng docker-compose.override.yml tự động load trong dev, và docker-compose.prod.yml riêng cho production:
# docker-compose.prod.yml
services:
backend:
command: npm start
deploy:
replicas: 2
resources:
limits:
cpus: '0.5'
memory: 512M
restart: always
Chạy production:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

So sánh Docker Compose với các công cụ khác
| Công cụ | Use case | Ưu điểm | Nhược điểm |
|---|---|---|---|
| Docker Compose | Local dev, small production | Đơn giản, phổ biến, good docs | Không orchestrate multi-host |
| Kubernetes (k8s) | Production, scale out | Auto-scaling, self-healing, ecosystem khổng lồ | Học curve dốc, overkill cho local |
| Podman Compose | Rootless, daemonless | Không cần root, tương thích Compose | Ecosystem nhỏ hơn Docker |
| Dev Containers | VS Code remote dev | Tích hợp IDE, shareable dev env | Phụ thuộc VS Code |
Troubleshooting thường gặp
1. Container khởi động chậm
Kiểm tra docker compose logs db. Nếu depends_on thiếu health check, backend có thể connect trước database sẵn sàng. Thêm health check + condition: service_healthy.
2. Port conflict
Nếu port 3000 đã bị process local chiếm, Compose báo Bind for 0.0.0.0:3000 failed. Giải pháp: đổi port trong ports hoặc kill process local (lsof -ti:3000 | xargs kill).
3. Volume permission
Trên Linux, mounted file ownership đổi sang root. Thêm user: "${UID}:${GID}" trong service, hoặc dùng chown trong Dockerfile.
4. Network connectivity
Services dùng tên service name làm hostname (db, redis). Không dùng localhost giữa các services — localhost trỏ về container hiện tại, không phải service khác.
Best practices
- .dockerignore: bỏ
node_modules,.git,.env. - Pin images: dùng
postgres:16.3-alpinethaylatest. - Health checks: mọi database/cache đều cần.
- Restart policy:
unless-stoppedcho dev,alwayscho prod. - Secrets: dùng
env_filehoặc Docker secrets, không hardcode. - Resource limits:
deploy.resourcesđể container không chiếm toàn bộ RAM.
Kết luận
Docker Compose là công cụ bắt buộc cho developer hiện đại. Một file docker-compose.yml thay thế hàng trang README hướng dẫn cài môi trường, loại bỏ “nhưng nó chạy được trên máy tôi”. Combo với hot reload + health checks + volume mounts cho dev loop nhanh nhất. Production nhỏ có dùng luôn, lớn hơn migrate sang Kubernetes.
