Docker Healthcheck Flapping - Container Marked Unhealthy in CI
A HEALTHCHECK reported the container unhealthy because the probe failed - usually it ran before the app finished starting, used a tool the image lacks, or had too tight a timeout. The app may be fine; the probe is mistuned.
What this error means
A container shows (health: starting) then flips to (unhealthy), and anything waiting on health (compose depends_on, an orchestrator) refuses to proceed. docker inspect shows the failing probe command and its output.
STATUS: Up 35 seconds (unhealthy)
# docker inspect --format '{{json .State.Health}}' shows:
# "ExitCode": 127, "Output": "/bin/sh: curl: not found"
# or the probe ran before the server was listeningCommon causes
No start-period for a slow-starting app
Without --start-period, failures during startup count against the container immediately, marking it unhealthy before it is ready to serve.
The probe tool is not in the image
A HEALTHCHECK CMD curl ... on an image without curl exits 127 every time, so the container is always unhealthy.
Timeout/interval too tight for the workload
A probe with a 1s timeout against an endpoint that takes longer under load fails intermittently, causing flapping.
How to fix it
Tune start-period, interval, and timeout
Give the app time to start and the probe enough timeout, using a tool that exists.
HEALTHCHECK --start-period=30s --interval=10s --timeout=5s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1Use a probe binary the image actually has
Prefer a built-in (wget on busybox/alpine, or the app’s own healthcheck) over assuming curl.
# alpine has wget, not curl, by default:
HEALTHCHECK CMD wget -qO- http://localhost:8080/health || exit 1
# or a language-native check that needs no extra toolHow to prevent it
- Always set
--start-periodfor apps with non-trivial startup time. - Use a healthcheck command whose binary is present in the image.
- Size timeout/interval to the endpoint’s real latency under load.