Docker HEALTHCHECK for a Web Server
A Docker HEALTHCHECK instruction runs a command inside the container on an interval and reports the container as healthy, unhealthy, or starting.
A container that is running is not necessarily serving. A HEALTHCHECK that probes a real endpoint lets orchestration and CI wait for actual readiness before sending traffic.
What it does
The HEALTHCHECK instruction defines a command Docker runs periodically inside the container. Exit 0 means healthy, exit 1 means unhealthy. The container reports a status of starting during the start period, then healthy or unhealthy, which docker ps and orchestrators can gate on.
Common usage
# Dockerfile: probe a real endpoint
HEALTHCHECK --interval=10s --timeout=3s --start-period=20s --retries=3 \
CMD curl -fsS http://localhost:80/health || exit 1
# if curl is absent (slim images), use wget
HEALTHCHECK CMD wget -q -O /dev/null http://localhost:80/ || exit 1Options
| Option | What it does |
|---|---|
| --interval=<d> | Time between checks (default 30s) |
| --timeout=<d> | Fail the check if it runs longer than this |
| --start-period=<d> | Grace period where failures do not count against retries |
| --retries=<n> | Consecutive failures before marking unhealthy |
| CMD ... | The probe command; exit 0 healthy, 1 unhealthy |
In CI
Wait for the container to report healthy before running integration tests: docker inspect --format "{{.State.Health.Status}}" <container> should read healthy. Set --start-period long enough for cold start so early failures do not flip the container to unhealthy. Prefer a real /health path over a bare TCP check so it reflects app readiness.
Common errors in CI
A container stuck unhealthy usually means the probe hits the wrong port or path, or curl/wget is missing from a slim image (add it or use the app runtime to probe). "curl: not found" or "wget: not found" inside the check indicates a missing tool. If the check passes but tests fail, the probe path is shallower than what the app truly needs to be ready; deepen it.