100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
YAML

Health Checks and Restart Policies

How Docker uses HEALTHCHECK instructions and restart policies to detect unhealthy containers and automatically recover from failures.

Docker Best PracticesIntermediate8 min readJul 8, 2026
Analogies

Why Health Checks Matter

A container process can be running while the application inside it is deadlocked, unresponsive, or unable to serve traffic. Docker's default process-based health monitoring only knows if the main process has exited, not whether the application is actually functional. HEALTHCHECK instructions let Docker actively probe application health and mark containers accordingly.

🏏

Cricket analogy: A batsman standing at the crease looks like he's still playing, but he could be concussed and unable to react to the next ball; the umpire's default check of 'is he on the field' doesn't catch this, just as Docker's process check misses an unresponsive app.

Defining a HEALTHCHECK in a Dockerfile

The HEALTHCHECK instruction defines a command Docker runs periodically inside the container. Based on the command's exit code, Docker reports the container as healthy, unhealthy, or starting.

🏏

Cricket analogy: A team doctor periodically runs a specific reflex test on a player during a match to check if they're actually fit, not just present on the field; based on the test's pass or fail result, the player is cleared, benched, or monitored, mirroring HEALTHCHECK's exit codes.

dockerfile
FROM nginx:1.27-alpine

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost/health || exit 1

Key options: '--interval' sets time between checks, '--timeout' is how long a check may run before being considered failed, '--start-period' gives the app time to boot before failures count toward the retry threshold, and '--retries' is the number of consecutive failures needed to mark the container unhealthy.

🏏

Cricket analogy: A fitness test schedule during a tour sets how often players are checked (--interval), how long each test may take before it's abandoned (--timeout), a grace period after a long flight before results count against them (--start-period), and how many failed tests before being ruled out (--retries).

Checking Health Status

Once a HEALTHCHECK is defined, 'docker ps' shows the health state next to the container status, and 'docker inspect' exposes the full health check log including recent exit codes and output.

🏏

Cricket analogy: The scoreboard shows a player's current fitness status (fit, injured, under assessment) at a glance, while the team doctor's full medical log records every past test result and reading, mirroring how 'docker ps' shows health state while 'docker inspect' exposes the full log.

bash
docker ps
# STATUS column shows: Up 2 minutes (healthy)

docker inspect --format='{{json .State.Health}}' mycontainer

Restart Policies

Restart policies tell the Docker daemon what to do when a container's main process exits. They are set with '--restart' on 'docker run' or the 'restart' key in Docker Compose, and they operate independently of HEALTHCHECK — Docker does not automatically restart a container just because it becomes unhealthy; only orchestrators like Kubernetes or Swarm act on health status to reschedule.

🏏

Cricket analogy: A team's policy on whether an injured bowler is automatically sent back in for the next over is separate from the doctor's fitness assessment; the coach decides restart policy, but only the team management (like an orchestrator) actually benches a player for poor form.

bash
# Never restart automatically (default)
docker run --restart no myapp

# Always restart, including after daemon restart
docker run --restart always myapp

# Restart unless the container was explicitly stopped
docker run --restart unless-stopped myapp

# Restart only on non-zero exit, up to 5 times
docker run --restart on-failure:5 myapp

'unless-stopped' is generally preferred over 'always' for long-running services because it respects an operator's explicit 'docker stop', while 'always' will restart the container even after a manual stop if the Docker daemon itself restarts.

Combining Health Checks with Compose

In Docker Compose, you can define both healthcheck and restart, and use 'depends_on' with a 'condition: service_healthy' so dependent services only start once a service reports healthy, avoiding race conditions on startup.

🏏

Cricket analogy: A tour schedule can require that the reserve wicketkeeper only takes the field once the main keeper has passed the team doctor's fitness check, avoiding the chaos of a keeper walking out mid-injury; this mirrors 'depends_on' with 'condition: service_healthy'.

yaml
services:
  api:
    image: myapp:1.4.0
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

  worker:
    image: myworker:1.0.0
    depends_on:
      api:
        condition: service_healthy

A container marked 'unhealthy' by plain Docker (not Swarm/Kubernetes) will keep running unless you build separate automation to react to it — HEALTHCHECK alone does not trigger a restart.

  • HEALTHCHECK actively probes application health, not just process liveness
  • start-period gives the app a grace window before failures count against retries
  • Restart policies (no, always, unless-stopped, on-failure) control automatic container restarts on the Docker daemon
  • Plain Docker does not restart a container just because it's marked unhealthy
  • Compose's depends_on with condition: service_healthy sequences startup correctly
  • 'unless-stopped' respects explicit manual stops, unlike 'always'

Practice what you learned

Was this page helpful?

Topics covered

#YAML#DockerKubernetesStudyNotes#DevOps#HealthChecksAndRestartPolicies#Health#Checks#Restart#Policies#StudyNotes#SkillVeris