HEALTHCHECK Done Right

A good healthcheck tests real readiness, sets sane intervals and a start period, and lets orchestrators route traffic only to healthy containers.

A container that is running is not necessarily working. A HEALTHCHECK teaches Docker (and Compose, Swarm, and load balancers) the difference, so traffic only goes to containers that can actually serve it.

Test something real

Curl a lightweight /healthz endpoint that confirms the app is truly ready — ideally checking its own critical dependencies. Do not just check that a port is open; a process can accept connections while being completely wedged.

Tune the timings

  • --interval — how often to check (e.g. every 30s).
  • --timeout — how long to wait before calling a check failed.
  • --retries — consecutive failures before marking unhealthy.
  • --start-period — grace window during slow startup where failures don't count. This is the flag people forget, and it's why apps flap on boot.

Use it in Compose

Pair a service healthcheck with depends_on: condition: service_healthy so your app waits for the database to be genuinely ready, not just started.

Example

Example · dockerfile
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --omit=dev

# Real readiness probe with a startup grace window
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD wget -qO- http://localhost:3000/healthz || exit 1

EXPOSE 3000
CMD ["node", "server.js"]

When to use it

  • A production API container uses a HEALTHCHECK with a start-period of 30 seconds so Docker does not declare it unhealthy while the JVM warms up.
  • Docker Compose uses the health check result to control depends_on so the migration service never runs before the database reports healthy.
  • An ops engineer monitors unhealthy containers by parsing docker inspect output in a cron job and paging on-call if any service fails.

More examples

Health check with start period

Sets a 20-second grace period so the container is not marked unhealthy before the app has had time to start.

Example · dockerfile
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --omit=dev
HEALTHCHECK \
  --interval=30s \
  --timeout=5s \
  --start-period=20s \
  --retries=3 \
  CMD wget -qO- http://localhost:3000/healthz || exit 1
CMD ["node", "index.js"]

Check health from the CLI

Extracts the current health status and the stdout of the most recent health probe in a single command.

Example · bash
# One-liner: show status and last check output
docker inspect myapp \
  --format '{{.State.Health.Status}} — {{(index .State.Health.Log 0).Output}}'

Compose depends on service_healthy

Configures Compose to start the api service only after the db's health check passes, not just when the container is created.

Example · yaml
services:
  db:
    image: postgres:16-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 10s

  api:
    build: .
    depends_on:
      db:
        condition: service_healthy

Discussion

  • Be the first to comment on this lesson.