Docker HEALTHCHECK Generator

Generate a HEALTHCHECK and see how long it takes to notice a problem. Read the first finding before relying on it, because Docker's response to an unhealthy container is nothing at all.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Generate. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A thirty second interval with three retries

Ninety seconds before anything notices, and Docker does nothing when it does

port: 8080
path: /healthz
interval: 30s
retries: 3

A distroless base

No shell and no curl, so a conventional check is permanently failing

FROM gcr.io/distroless/static:nonroot
EXPOSE 8080

No start period

Boot failures count against the retries, so a slow starter never becomes healthy

port: 3000
interval: 10s
retries: 3

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Expecting an unhealthy container to be restarted

    Plain Docker records the state and does nothing. A restart policy only reacts to the process exiting, and an unhealthy container has not exited.

    Instead:Use the state for visibility and for Compose's depends_on. Anything that acts on it has to be Swarm, an orchestrator or a watcher you run.

  2. Leaving the start period at zero

    Failures while the application is still booting count against the retries, so a slow starter is marked unhealthy before it has ever been ready.

    Instead:Set --start-period comfortably longer than the slowest cold start.

  3. Using curl in a check on a distroless or Alpine base

    The binary is not there. The check exits 127, which counts as a failure, so the container is permanently unhealthy.

    Instead:Use the language runtime already in the image, or copy in a small static health binary.

A HEALTHCHECK records a state and takes no action

A restart policy reacts to the process exiting, and an unhealthy container has not exited. So it sits there, marked unhealthy, still published and still receiving traffic, indefinitely.

What acts on the state, and what does not

Swarm replaces an unhealthy task and Kubernetes has a liveness probe. Plain Docker has neither. Compose can wait for it with depends_on and condition: service_healthy, which is a startup ordering feature rather than a recovery one. If something must restart on unhealthy, that something has to be you.

Time to unhealthy is start period plus retries times interval

Not the interval alone. With a 30 second interval and three retries a failure takes ninety seconds to register, during which the container is reported healthy and anything routing on health keeps sending traffic.

Without a start period, boot failures count against the retries

A container that takes forty seconds to open its port and has a thirty second interval is marked unhealthy before it has finished starting. Anything waiting on service_healthy then gives up, so a slow dependency fails a stack that would have worked. Failures during the start period do not count, and a success ends it early.

The check has to exist inside the image

distroless and scratch have no shell, so both CMD-SHELL and curl are absent. Alpine has a shell and no curl. A missing command exits 127, which counts as a failure, so the container is permanently unhealthy for a reason that looks like the application.

Only 0 and 1 mean anything

0 is healthy, 1 is unhealthy, 2 is reserved and anything else is treated as unhealthy. A check that pipes through something returning 2 on partial success reports unhealthy for a reason that is nowhere in the output. End it with an explicit exit.

Every check costs the container's own resources

It starts a process in the container's cgroup, so it uses the container's CPU quota and memory limit. On a tight limit a heavy check competes with the application, and across hundreds of containers a one-second interval is a real fraction of the host.

More docker tools

Docker Container Image Reference Parser Is that a registry or a Docker Hub user? Dockerfile Linter What this image will do to you later docker run to Kubernetes YAML And the flags that have no equivalent Docker Compose to Kubernetes And why depends_on has no equivalent Docker Logging Driver Generator json-file never rotates Dockerfile Non-Root USER Generator Numeric, or Kubernetes rejects it Docker OCI Image Labels Generator One of them actually does something Docker Hub Pull Rate Limit Calculator Counted per IP, not per person Docker Registry Storage Calculator Deleting a tag frees nothing Docker Build Context Analyzer All of it uploads before anything runs Docker Compose to docker run Converter Names stop resolving Docker Compose Version Migrator version: is obsolete now Docker Compose Network and Port Viewer Everything reaches everything Docker Command Explainer Which flags hand over the host Docker BuildKit Cache Mount Generator apt deletes the cache you just mounted Docker BuildKit Secret Mount Generator ARG is in docker history forever Docker .dockerignore Pattern Tester *.log does not match logs/app.log Docker Image Manifest Viewer unknown/unknown is not broken Docker Image Config Viewer Anyone who can pull can read your Env Docker Registry Token Decoder Check the scope before the credentials Docker Network Subnet Calculator 31 networks, then it stops Docker History Analyzer The rm did not save anything Docker Run to Compose Converter Some flags have no equivalent Docker CMD and ENTRYPOINT Tester Why docker stop takes ten seconds Docker Port Mapping Tester -p reaches past your firewall Docker -v to --mount Converter -v invents missing directories Docker Restart Policy Simulator The backoff resets after ten seconds Docker Exit Code Explainer 137 is two different problems Docker CPU Limit Converter --cpu-shares limits nothing Docker Memory Limit Calculator -m 512m allows a gigabyte Docker Compose Interpolation Tester An unset variable is an empty string Docker Environment Variable Precedence Tester Your shell does not reach the container Docker Compose Override Merge Previewer An override can add a port, never remove one Dockerfile Multi-Stage Build Analyzer Which stages reach the image Dockerignore Validator It is not .gitignore

Elsewhere on the site