Cấu hình Healthcheck và depends_on trong Docker Compose đúng cách
Hướng dẫn Docker Compose Healthcheck và depends_on: service_started, service_healthy, service_completed_successfully, PostgreSQL, Node.js, migration jobs, retry và debug.
ShanverseCập nhật 10 phút đọc— lượt xemĐang tải lượt xem
Docker
Docker Compose
Vấn đề: Container đã chạy nhưng ứng dụng chưa sẵn sàng
Một Container có thể ở trạng thái running trong khi process bên trong vẫn đang:
Khởi tạo database.
Chạy recovery hoặc replay log.
Load model/configuration.
Compile code.
Mở connection pool.
Chờ migration hoàn tất.
Mermaid
Loading diagram…
Bình luận
running chỉ nói main process chưa thoát. healthy nói healthcheck đang trả kết quả thành công.
Health status hoạt động thế nào?
Khi có healthcheck, Docker theo dõi ba trạng thái:
Healthcheck command:
Exit code 0: thành công.
Exit code khác 0: thất bại.
Health status không thay thế trạng thái process. Một Container có thể running + unhealthy.
Cấu trúc healthcheck
Ý nghĩa:
test: lệnh kiểm tra.
interval: thời gian giữa các lần kiểm tra.
timeout: thời gian tối đa cho một lần.
retries: số lần thất bại liên tiếp trước khi unhealthy.
start_period: thời gian warm-up; failure trong giai đoạn này không bị tính như failure thông thường.
Chọn timing theo SLO và thời gian khởi động thật, không copy một con số cho mọi service.
CMD và CMD-SHELL
Exec form: CMD
Không qua shell, ít vấn đề quoting hơn.
Shell form: CMD-SHELL
Dùng khi cần environment expansion, pipe hoặc &&.
Hai dấu $ giữ biến cho shell bên trong Container. Nếu dùng ${POSTGRES_USER}, Compose có thể interpolate từ host trước.
Healthcheck chạy ở đâu?
Lệnh chạy bên trong Container được kiểm tra.
Vì vậy, với API Container:
là đúng vì API tự kiểm tra chính nó.
Ngược lại, để API gọi PostgreSQL Container:
mới đúng. localhost:5432 vẫn là API Container.
Healthcheck cho Node.js không cần curl
Image tối giản thường không có curl. Với Node.js hiện đại, dùng built-in fetch:
Hoặc tạo file rõ ràng hơn:
Dockerfile:
Compose:
Liveness và readiness khác nhau
Liveness
Process còn hoạt động và event loop chưa bị treo.
Readiness
Service có thể nhận traffic có ý nghĩa: initialization hoàn tất, dependency quan trọng truy cập được hoặc connection pool sẵn sàng.
Docker chỉ có một health status cho Container. Hãy quyết định healthcheck đại diện liveness hay readiness theo mục đích. Vì depends_on: service_healthy dùng health status để gate startup, readiness thường hữu ích ở đây.
Đừng để health endpoint gọi toàn bộ hệ thống bên ngoài; một dependency phụ không hoạt động có thể làm cả stack bị cascade unhealthy.
Healthcheck cho PostgreSQL
pg_isready xác nhận server đang chấp nhận connection. Nó không chứng minh migration đã chạy, schema đúng hoặc application user có đủ quyền. Dùng migration job riêng để kiểm tra bước đó.
Healthcheck cho MongoDB và Redis
MongoDB:
Khi bật authentication, healthcheck phải dùng cơ chế credential an toàn và đúng database xác thực. Không hard-code password vào command.
Redis:
depends_on dạng ngắn: chỉ đảm bảo thứ tự start
Compose tạo/start postgres trước api, nhưng không đợi PostgreSQL healthy. Dạng này không giải quyết race condition readiness.
depends_on dạng dài và ba condition
service_started
Dependency đã được start, chưa chắc sẵn sàng.
service_healthy
Dependency phải có healthcheck và đạt healthy.
service_completed_successfully
Phù hợp với one-shot job như migration, seed hoặc generate artifact. Job phải kết thúc với exit code 0.
Stack hoàn chỉnh: PostgreSQL → Migration → API → Worker
Mermaid
Loading diagram…
Startup flow:
PostgreSQL Container start.
Compose đợi PostgreSQL healthy.
Migration chạy và phải exit 0.
API start sau khi database healthy và migration thành công.
Worker start sau khi API healthy.
Nếu migration exit khác 0, API không được start theo dependency condition.
restart: true bên trong depends_on
Trong Compose hỗ trợ tính năng này, khi dependency được restart/update bằng một thao tác Compose rõ ràng, dependent có thể được restart sau đó để reconnect sạch.
Nó không có nghĩa API tự restart mỗi khi PostgreSQL crash hoặc runtime restart tự động. Kiểm tra compatibility bằng:
Dependency tùy chọn với required: false
Một số Compose version hỗ trợ dependency không bắt buộc:
Phù hợp với observability local không bắt buộc. Compose có thể cảnh báo thay vì chặn stack. Kiểm tra version/Compose Spec đang dùng trước khi áp dụng.
Restart policy khác healthcheck và depends_on
Restart policy xử lý main process thoát. Nó không:
Đợi dependency ready.
Chạy migration.
Tự restart chỉ vì healthcheck unhealthy.
Khôi phục business connection trong application.
Ba cơ chế có vai trò khác nhau:
depends_on chỉ giúp lúc khởi động
Sau khi stack chạy, database có thể restart. Compose không liên tục dừng API để tái áp dependency graph.
Application cần:
Connection timeout.
Retry với exponential backoff và jitter.
Reconnect của driver.
Circuit breaker khi phù hợp.
Graceful shutdown.
Readiness phản ánh trạng thái thật.
Ví dụ retry đơn giản:
Dùng healthcheck từ Dockerfile hay Compose?
Dockerfile:
Ưu điểm: health contract đi cùng Image.
Compose có thể override theo môi trường:
Hoặc vô hiệu healthcheck từ Image khi có lý do rõ ràng:
Không disable chỉ để stack “xanh”; hãy sửa healthcheck hoặc service.
Khởi động và đợi stack healthy
Validate trước:
Chạy:
Với Compose hỗ trợ --wait:
Lệnh phù hợp cho local automation và CI vì trả lỗi nếu service không đạt trạng thái mong đợi trong timeout.
Theo dõi và debug health status
Xem trạng thái:
Xem chi tiết Container và các lần healthcheck gần nhất:
Theo dõi event:
Đọc log service:
Chạy health command thủ công:
Vì sao healthcheck luôn fail?
Tool không tồn tại
Dùng tool có sẵn trong Image hoặc health script của chính runtime. Đừng cài cả package chỉ cho một check nếu có cách nhỏ hơn.
App bind sai interface
App phải bind 0.0.0.0 để Container khác truy cập, dù self-health qua localhost có thể vẫn pass.
Endpoint yêu cầu authentication
Health endpoint nội bộ nên có thiết kế phù hợp, không nhúng token nhạy cảm vào healthcheck command.
Timeout quá ngắn
Đo latency thật và đặt timeout có margin hợp lý.
start_period quá ngắn
Service bị đánh dấu unhealthy trong lúc warm-up bình thường.
Biến bị Compose interpolate nhầm
Dùng $${VAR} khi biến phải được expand bên trong Container.
Healthcheck quá nặng
Query lớn hoặc gọi nhiều upstream tạo tải, gây false negative và cascading failure.
Anti-pattern phổ biến
Dùng sleep 30
Thời gian cố định vừa chậm vừa không đảm bảo dependency ready.
Chỉ dùng short depends_on
Nó không đợi health status.
Healthcheck gọi mọi dependency
Một service phụ lỗi kéo toàn bộ stack thành unhealthy.
Dùng healthcheck để chạy migration
Healthcheck lặp lại; migration nên là one-shot job với service_completed_successfully.
Ghi password trực tiếp trong health command
Command và output có thể xuất hiện trong inspect/log. Dùng credential mechanism phù hợp và check tối thiểu.
Tạo dependency vòng tròn
Thiết kế dependency graph một chiều.
Tin rằng healthy nghĩa là business logic hoàn hảo
Healthcheck chỉ kiểm tra contract hẹp. Monitoring, tracing, SLO và synthetic tests vẫn cần thiết.
Checklist production
Mỗi dependency quan trọng có healthcheck nhẹ và có ý nghĩa.
depends_on dùng condition đúng thay vì chỉ short syntax.
Migration là one-shot job và phải exit 0.
API có retry/reconnect sau startup.
Healthcheck không chứa secret trực tiếp.
Tool dùng trong test có sẵn trong Image.
interval, timeout, retries, start_period dựa trên dữ liệu thật.
Health endpoint có timeout và không tạo tải lớn.
Không kỳ vọng unhealthy tự restart Container.
docker compose config được chạy trong CI.
Automation dùng --wait khi Compose version hỗ trợ.
Alerting dựa trên cả health status và metric ứng dụng.
Docker Compose khi nào không còn đủ? So sánh Kubernetes và Docker Swarm về multi-host, self-healing, scaling, rolling update, networking, secrets và lộ trình migration production.
Hướng dẫn Live Reload và Hot Reload với Docker Compose cho Node.js, TypeScript, Vite và Next.js: bind mounts, Compose Watch, node_modules, polling, quyền file và debug.
Hướng dẫn Docker Compose cho Node.js với hai cấu hình docker-compose.yml hoàn chỉnh: PostgreSQL và MongoDB, kèm healthcheck, service discovery, volume, bảo mật và debug.