iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Healthchecks

Docker healthchecks: HEALTHCHECK in Dockerfile, compose health, and the patterns for reliable orchestrator decisions.

Docker — healthchecks

EXAMPLE
# ===== Why =====
# Containers can be RUNNING but UNHEALTHY (deadlocked, OOM-ed thread, db disconnected).
# Healthchecks let Docker / orchestrators detect this and replace the container.

# ===== HEALTHCHECK in Dockerfile =====
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --omit=dev

HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=20s \
  CMD wget -qO- http://localhost:3000/healthz || exit 1

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

# Options:
# --interval     between checks (default 30s)
# --timeout      max check duration (default 30s)
# --retries      failures before unhealthy (default 3)
# --start-period grace period before failures count (default 0s)

# ===== Check states =====
# starting  -> within start-period; failures don't count
# healthy   -> last check passed
# unhealthy -> retries exhausted

docker ps --format 'table {{.Names}}\t{{.Status}}'
# NAME    STATUS
# api     Up 5 minutes (healthy)

# ===== docker compose =====
services:
  api:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:3000/healthz"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s

  app:
    image: myapp:1
    depends_on:
      db:
        condition: service_healthy        # wait for db healthcheck

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s

# ===== Application healthcheck shape =====
# A good /healthz:
# - Returns 200 if the app is RUNNING (not crashed)
# - Returns 500 if a CRITICAL dependency is down
# - Does NOT do heavy work (cheap to call)

# Distinguish:
# /healthz       liveness  (is the process alive?)
# /readyz        readiness (is it ready to receive traffic?)

# Kubernetes uses both; Docker only has one HEALTHCHECK.

# ===== Common patterns =====
# Express example:
app.get('/healthz', (req, res) => res.json({ ok: true }));
app.get('/readyz', async (req, res) => {
  try {
    await db.ping();
    await cache.ping();
    res.json({ ok: true });
  } catch (e) {
    res.status(500).json({ ok: false, error: e.message });
  }
});

# ===== Orchestrator behavior =====
# Docker: unhealthy containers stay running but appear (unhealthy) in ps
# Compose: depends_on + service_healthy waits before starting dependents
# Swarm: replaces unhealthy tasks
# Kubernetes: ignores HEALTHCHECK in Dockerfile; uses pod liveness/readiness probes

# ===== Patterns =====
# - HEALTHCHECK in Dockerfile for portable images
# - Cheap, fast endpoints; no DB calls in liveness
# - depends_on: condition: service_healthy in compose
# - Distinguish liveness vs readiness

# ===== Pitfalls =====
# - Healthcheck calling 'localhost' before app listens -> false failures
# - Healthcheck that hits external services -> coupled failure modes
# - Long timeouts hiding hangs
# - No start_period on slow-booting apps -> instant unhealthy

Why it matters

HEALTHCHECK in Dockerfile + healthcheck in compose make container health observable. Keep them cheap, distinguish liveness from readiness, use depends_on: service_healthy to sequence startup. Kubernetes uses its own probes; Docker / compose lean on this.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
HEALTHCHECK --interval=30s CMD wget -qO- http://localhost:3000/health || exit 1
Try it Yourself »

Discussion

Loading…