Docker Production: Từ Development Đến Deploy Thực Tế
"It works on my machine" — câu nói kinh điển mà Docker sinh ra để giải quyết. Docker đóng gói app + dependencies thành container chạy giống nhau ở mọi nơi: laptop developer, staging server, hay production cluster. Theo Docker 2024 survey, 87% enterprises đã sử dụng containers trong production. Nhưng Docker cho development khác Docker cho production 180 độ: dev dùng volumes, hot-reload, debug ports mở rộng. Production cần: multi-stage builds (image nhỏ gọn), security hardening (non-root user), health checks (self-healing), resource limits (prevent OOM). Bài viết này là production checklist 10 điểm từ kinh nghiệm thực tế deploy BanhCuonFlow — mỗi điểm đều có giải thích tại sao quan trọng và cách thực hiện cụ thể.
Tại Sao Docker Development ≠ Docker Production?
Trong development: bạn mount source code bằng bind volumes để
hot-reload, expose debug ports (5005, 9229), chạy as root cho tiện,
không set resource limits, dùng
docker-compose up và xong. Nếu deploy production với cùng config
này: bạn sẽ gặp container chiếm hết RAM server (vì không giới hạn memory),
security vulnerabilities (vì root user), image quá lớn (vì chứa cả build tools),
và không tự recovery khi app crash (vì không health check). Docker official
documentation khuyến cáo: "Production containers MUST be treated as immutable infrastructure" — build image 1 lần, cấu hình qua environment variables, không modify container
sau khi deploy.
Production Checklist: 10 Điểm Bắt Buộc
① Multi-Stage Build
Stage 1 (build): chứa SDK, compiler, build tools — dùng để compile code, restore dependencies. Stage 2 (runtime): chỉ copy output từ stage 1, dùng base image nhỏ (alpine hoặc distroless). Kết quả: BanhCuonFlow .NET image từ 1.5GB (build stage) giảm xuống 200MB (runtime stage). Image nhỏ hơn = pull nhanh hơn khi deploy = ít CVE hơn vì ít packages cài đặt = attack surface nhỏ hơn đáng kể. Sử dụng BuildKit và cache mounts để tăng tốc build times lặp lại.
② Non-Root User
KHÔNG BAO GIỜ chạy container as root trong production.
Nếu attacker compromise container chạy root → họ có full access đến filesystem,
network, và có thể escape ra host system. Thêm USER appuser
trong Dockerfile, tạo user với adduser --disabled-password. BanhCuonFlow: tất cả containers chạy non-root, file permissions
restricted chỉ read cho app code, write chỉ cho logs và uploads
directory cụ thể.
③ Health Checks
HEALTHCHECK CMD curl -f http://localhost/health || exit 1
— Docker dùng health check để biết container healthy không. Unhealthy
→ tự động restart (Docker Swarm) hoặc replace pod (Kubernetes). Health
check nên verify application-level health, không chỉ
process running: BanhCuonFlow /health endpoint kiểm tra DB
connection, Redis connection, disk space — nếu bất kỳ thứ gì fail, endpoint
trả 503 và container được restart. Configure: interval 30s, timeout 10s,
start-period 60s (cho app warm up), retries 3.
④ Resource Limits
deploy: resources: limits: memory: 2G, cpus: '2'. Không
set limits → 1 container memory leak có thể OOM kill toàn bộ server,
ảnh hưởng tất cả containers khác trên cùng host. Luôn set cả --memory
và --memory-swap bằng nhau để disable swap — tránh latency
spikes không dự đoán được. BanhCuonFlow production specs: API container
2GB RAM / 2 CPU, PostgreSQL 4GB / 2 CPU, Redis 512MB / 1 CPU. Monitor
actual usage và điều chỉnh limits theo workload thực tế.
⑤ .dockerignore
File .dockerignore quan trọng ngang .gitignore. Exclude: .git, node_modules, test
files, local env files, IDE configs, secrets. Không exclude → build
context lớn → build chậm + risk leak sensitive data vào image (API
keys trong .env files bị copy vào image layers, ai pull image đều
đọc được).
⑥ Environment Variables, Không Hardcode
Database connection string, API keys, secrets → environment
variables hoặc Docker secrets (encrypted at rest). KHÔNG hardcode trong Dockerfile hoặc source code — mọi thứ hardcoded trong image layer
đều có thể extract bằng docker history. BanhCuonFlow: .env
file cho Docker Compose, injected at runtime qua env_file
directive, với file permissions 600 (chỉ owner đọc được).
⑦ Logging to stdout/stderr
Log ra console (stdout cho info, stderr cho errors), không log ra file trong container. Docker logging driver capture stdout → forward đến ELK Stack, Grafana Loki, CloudWatch, hoặc bất kỳ centralized logging system nào. Log files trong container = mất khi container restart, khó aggregate, tốn disk space. BanhCuonFlow dùng Serilog output console + JSON format để dễ parse bởi log aggregators.
⑧ Named Volumes cho Persistent Data
Database data, uploaded files → Docker named volumes, KHÔNG bind
mounts. Named volumes managed by Docker engine, survive container
recreate/upgrade. BanhCuonFlow: pgdata volume cho PostgreSQL
data, uploads volume cho user files. Backup volumes định
kỳ bằng docker run --volumes-from + tar/rsync.
⑨ Reverse Proxy (Nginx)
Nginx đứng trước app server làm reverse proxy: SSL/TLS termination (Let's Encrypt free certificates), static file serving (tránh load app server), rate limiting (prevent DDoS), request buffering, gzip compression. App server KHÔNG expose trực tiếp internet — giảm attack surface đáng kể. BanhCuonFlow production: Nginx → API (.NET Kestrel) + frontend (static files pre-built).
⑩ Backup Strategy
Automated daily backup: pg_dump → compress gzip → upload
đến S3/external storage (off-site, khác server với database). Test restore monthly — backup không test restore = không có backup (bạn chỉ có file dump
mà không biết có restore được không). BanhCuonFlow: PostgreSQL WAL archiving
+ daily base backup = point-in-time recovery (restore
về bất kỳ thời điểm nào trong 7 ngày). Retention: daily backups giữ 7
ngày, weekly giữ 4 tuần, monthly giữ 12 tháng.
Image Scanning: Bảo Mật Trước Khi Deploy
Mỗi Docker image chứa OS packages, libraries, runtime — bất kỳ thứ nào
trong đó đều có thể chứa CVE (Common Vulnerabilities and Exposures). Trivy
(open-source, Aqua Security) quét image trong CI/CD pipeline: trivy image myapp:latest → liệt kê tất cả CVE, severity (Critical/High/Medium/Low), và fix version
nếu có. Docker Scout (tích hợp Docker Desktop) cung cấp continuous monitoring.
Nguyên tắc: image có CVE Critical hoặc High → pipeline fail, không cho deploy.
Rebuild image weekly với base image mới nhất để apply security patches tự
động.