Files
MajorWiki/02-selfhosting/docker/docker-healthchecks.md

3.9 KiB

title, domain, category, tags, status, created, updated
title domain category tags status created updated
Docker Healthchecks selfhosting docker
docker
healthcheck
monitoring
uptime-kuma
compose
published 2026-03-23 2026-03-23

Docker Healthchecks

A Docker healthcheck tells the daemon (and any monitoring tool) whether a container is actually working — not just running. Without one, a container shows as Up even if the app inside is crashed, deadlocked, or waiting on a dependency.

Why It Matters

Tools like Uptime Kuma report containers without healthchecks as:

Container has not reported health and is currently running. As it is running, it is considered UP. Consider adding a health check for better service visibility.

A healthcheck upgrades that to a real (healthy) or (unhealthy) status, making monitoring meaningful.

Basic Syntax (docker-compose)

healthcheck:
  test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 30s
Field Description
test Command to run. Exit 0 = healthy, non-zero = unhealthy.
interval How often to run the check.
timeout How long to wait before marking as failed.
retries Failures before marking unhealthy.
start_period Grace period on startup before failures count.

Common Patterns

HTTP service (wget — available in Alpine)

healthcheck:
  test: ["CMD", "wget", "-q", "--spider", "http://localhost:2368/"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 30s

HTTP service (curl)

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 30s

MySQL / MariaDB

healthcheck:
  test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret"]
  interval: 10s
  timeout: 5s
  retries: 3
  start_period: 20s

PostgreSQL

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

Redis

healthcheck:
  test: ["CMD", "redis-cli", "ping"]
  interval: 10s
  timeout: 5s
  retries: 3

TCP port check (no curl/wget available)

healthcheck:
  test: ["CMD-SHELL", "nc -z localhost 8080 || exit 1"]
  interval: 30s
  timeout: 5s
  retries: 3

Using Healthchecks with depends_on

Healthchecks enable proper startup ordering. Instead of a fixed sleep, a dependent container waits until its dependency is actually ready:

services:
  app:
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 20s

This prevents the classic race condition where the app starts before the database is ready to accept connections.

Checking Health Status

# See health status in container list
docker ps

# Get detailed health info including last check output
docker inspect --format='{{json .State.Health}}' <container> | jq

Ghost Example

Ghost (Alpine-based) uses wget rather than curl:

healthcheck:
  test: ["CMD", "wget", "-q", "--spider", "http://localhost:2368/ghost/api/v4/admin/site/"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 30s

Gotchas & Notes

  • Alpine images don't have curl by default — use wget or install curl in the image.
  • start_period is critical for slow-starting apps (databases, JVM services). Failures during this window don't count toward retries.
  • CMD vs CMD-SHELL — use CMD for direct exec (no shell needed), CMD-SHELL when you need pipes, &&, or shell builtins.
  • Uptime Kuma will pick up Docker healthcheck status automatically when monitoring via the Docker socket — no extra config needed.

See Also