2026年11月14日
2026年11月14日
Docker Health Checks: Set Up HEALTHCHECK, Compose and docker run
This article is a localized edition of the Japanese original. Read the Japanese original
A Docker health check runs a given command inside the container at regular intervals and uses the result to decide whether the container is "responding correctly". Even when the process is running, it can tell you that the web server is returning errors or that the database is not yet accepting connections.
This article explains three ways to configure a health check (Dockerfile, Docker Compose and docker run) and how to check the results. Behavior was confirmed as of October 2026 with Docker Engine 29, Docker Compose v5 and the nginx:1.28 and mariadb:11 images.
How health checks work
A container with a health check is in one of these three states.
| State | Meaning |
|---|---|
starting |
Just started. No verdict yet |
healthy |
The check command succeeded (exit code 0) |
unhealthy |
The check command failed a set number of times in a row |
The check command signals success with exit code 0 and failure with 1 (2 is reserved; do not use it).
Note: Docker Engine on its own does not restart a container when it becomes unhealthy. The --restart policy applies only when the container's process exits. How to deal with this is explained later in "Unhealthy containers are not restarted".
Configure it in a Dockerfile
Writing a HEALTHCHECK instruction in a Dockerfile adds the health check to every container created from that image.
FROM nginx:1.28
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --start-interval=2s --retries=3 \
CMD curl -fsS -o /dev/null http://localhost/ || exit 1
The -f option of curl makes it exit with code 22 when the HTTP status is 400 or higher. || exit 1 turns every failure into exit code 1.
| Option | Default | Meaning |
|---|---|---|
--interval |
30s |
Time between checks |
--timeout |
30s |
Time limit for one check. Exceeding it counts as a failure |
--start-period |
0s |
Grace period after startup. Failures during it are not counted (a success makes it healthy immediately) |
--start-interval |
5s |
Time between checks during the grace period (Docker Engine 25.0 and later) |
--retries |
3 |
Consecutive failures needed to become unhealthy |
Without --start-interval, the first check runs only after --interval has passed since startup, so the container stays starting for about 30 seconds before it becomes healthy.
If the base image defines a health check and you want to disable it, write HEALTHCHECK NONE.
Make sure the check command exists in the image
The check command runs inside the container, so it must exist in the image. The official nginx image includes curl, but many images include neither curl nor wget. Check beforehand.
docker run --rm nginx:1.28 sh -c 'command -v curl wget'
If nothing is printed, neither is installed. In that case, install one in the Dockerfile or use a check command the application itself provides (for example healthcheck.sh in the official mariadb image).
Configure it in Docker Compose
In a Compose file (compose.yaml), write healthcheck for each service.
services:
db:
image: mariadb:11
environment:
MARIADB_ROOT_PASSWORD: example
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
start_interval: 2s
web:
image: nginx:1.28
ports:
- "8080:80"
healthcheck:
test: ["CMD-SHELL", "curl -fsS -o /dev/null http://localhost/ || exit 1"]
interval: 30s
timeout: 5s
retries: 3
depends_on:
db:
condition: service_healthy
- If
teststarts withCMD, the remaining elements are run as the command as-is. WithCMD-SHELL, the following string is run by the shell (/bin/sh -c), so you can use||and the like condition: service_healthyunderdepends_onstartswebonly afterdbishealthy. This prevents the app from starting before the database is ready and failing to connect- To disable a health check defined in the image, write
disable: trueunderhealthcheck:
When you bring it up, you can see web start only after db becomes Healthy.
docker compose up -d
Container hc-db-1 Started
Container hc-db-1 Waiting
Container hc-db-1 Healthy
Container hc-web-1 Starting
Container hc-web-1 Started
You do not need a line such as version: '3.8' at the top of the Compose file. Current Docker Compose ignores it and warns that it is "obsolete".
Configure it with docker run
You can also add a health check when creating a container, without rebuilding the image.
docker run -d --name my-nginx \
--health-cmd='curl -fsS -o /dev/null http://localhost/ || exit 1' \
--health-interval=30s \
--health-timeout=5s \
--health-retries=3 \
--health-start-period=10s \
nginx:1.28
--health-cmd is run by the shell. To disable a health check defined in the image, add --no-healthcheck.
Health check settings are fixed when the container is created. You cannot add one to a running container later, so recreate the container to change them.
Check the status
The STATUS column of docker ps shows the health check state.
docker ps --format '{{.Names}} {{.Status}}'
my-nginx Up 5 seconds (healthy)
docker inspect shows the detailed results.
# State only
docker inspect --format '{{.State.Health.Status}}' my-nginx
# Exit codes and output of recent checks
docker inspect --format '{{json .State.Health}}' my-nginx
{"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2026-10-29T17:39:31.069523955Z","End":"2026-10-29T17:39:31.146682497Z","ExitCode":0,"Output":""}]}
FailingStreak is the number of consecutive failures, and ExitCode and Output in Log are the exit code and output of the check command. When the container becomes unhealthy, Output holds the reason for the failure. To show only the exit codes and output side by side:
docker inspect --format '{{range .State.Health.Log}}{{.ExitCode}} {{.Output}}{{end}}' my-nginx
1 curl: (22) The requested URL returned error: 403
You can also list only unhealthy containers, or watch events when the state changes.
# Show only unhealthy containers
docker ps --filter health=unhealthy
# Keep showing health state changes (Ctrl+C to stop)
docker events --filter event=health_status
Unhealthy containers are not restarted
In testing, a container started with --restart unless-stopped became unhealthy, but its restart count (RestartCount) stayed at 0. Docker Engine on its own does not restart containers based on health check results.
If you want containers restarted when they are unhealthy, these are your options.
- Run it as a Docker Swarm service: in Swarm mode, an
unhealthytask (container) is stopped and replaced with a new one - Use Kubernetes: a container whose liveness probe fails is restarted
- Restart it yourself: run a command that finds and restarts
unhealthycontainers periodically, for example from cron
# Restart all unhealthy containers
docker ps -q --filter health=unhealthy | xargs -r docker restart
A restart fixes only transient problems. If a container keeps becoming unhealthy, investigate with the Output from docker inspect and the container logs (docker logs).
Things to keep in mind
- Keep checks light: the check runs inside the container at every interval. Avoid heavy work (such as large database queries) and use a page or command that just returns a response
- Do not depend on external services: if the check includes an external API or similar, an outage of that service makes your own container
unhealthytoo - Match
--timeoutand--start-periodto real behavior: for apps that start slowly, a--start-periodthat is too short counts failures during startup and the container becomesunhealthy - Check via
localhost: the check runs inside the container, so connect to the port the container listens on, not the host port (for example8080)
Summary
- A health check runs a command inside the container periodically: exit code 0 means
healthy, and repeated failures meanunhealthy - You can configure it with
HEALTHCHECKin a Dockerfile,healthcheckin Compose, or--health-*withdocker run --start-periodand--start-intervaltune the verdict right after startupdepends_onwithcondition: service_healthyin Compose starts a service only after its dependency is ready- Docker Engine alone does not restart
unhealthycontainers. Handle this with Swarm, Kubernetes or your own mechanism
Related articles:
- Docker Compose basics
- Controlling startup order with depends_on in Docker Compose
- Automatically restarting Docker containers
- Configuring Kubernetes health checks (probes)
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)