Docker Compose cho dự án thực tế: từ dev đến production
Nhiều tutorial Docker Compose chỉ dừng ở mức "chạy WordPress + MySQL". Nhưng dự án thực tế phức tạp hơn nhiều. Bài này chia sẻ setup mình đang dùng cho production.
Cấu trúc thư mục
project/
├── docker-compose.yml # Base config
├── docker-compose.dev.yml # Dev overrides
├── docker-compose.prod.yml # Prod overrides
├── .env.dev
├── .env.prod
└── services/
├── api/
│ └── Dockerfile
├── worker/
│ └── Dockerfile
└── nginx/
└── nginx.conf
```
## Base compose file
```yaml
services:
api:
build: ./services/api
env_file: .env
depends_on:
db:
condition: service_healthy
networks:
- backend
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: pg_isready -U postgres
interval: 5s
retries: 5
networks:
- backend
redis:
image: redis:7-alpine
networks:
- backend
volumes:
pgdata:
networks:
backend:
```
## Dev overrides
```yaml
# docker-compose.dev.yml
services:
api:
volumes:
- ./services/api:/app # Hot reload
ports:
- "8000:8000"
command: uvicorn main:app --reload --host 0.0.0.0
db:
ports:
- "5432:5432" # Access from host
```
Chạy dev: `docker compose -f docker-compose.yml -f docker-compose.dev.yml up`
## Prod overrides
```yaml
# docker-compose.prod.yml
services:
api:
restart: always
deploy:
resources:
limits:
memory: 512M
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./services/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- api
```
## Tips từ production
1. **Luôn dùng healthcheck** — `depends_on` không đợi service sẵn sàng, chỉ đợi container start
2. **Pin image version** — `postgres:16-alpine`, không phải `postgres:latest`
3. **Giới hạn memory** — Tránh một container ăn hết RAM
4. **Log rotation** — Không set thì log file sẽ phình to vô hạn
5. **Named volumes cho data** — Bind mount chỉ dùng cho dev, production dùng named volume
---
Bạn có tips nào khác cho Docker Compose production không? Share nhé!
All rights reserved