Healthchecks in Docker definieren - mehr als nice-to-have

Healthchecks in Docker definieren - mehr als nice-to-have

Ein Healthcheck meldet Docker, ob ein Container wirklich funktioniert — nicht nur ob er läuft. Das ist die Grundlage für zuverlässige Abhängigkeiten und automatische Selbstheilung.

Healthcheck im Dockerfile

FROM nginx:alpine

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

Optionen:

| Option | Bedeutung | Default |
|---|---|---|
| --interval | Wie oft wird geprüft | 30s |
| --timeout | Maximale Ausführungszeit des Tests | 30s |
| --retries | Fehlschläge bis unhealthy | 3 |
| --start-period | Anlaufzeit, Fehlschläge zählen nicht | 0s |

start-period ist wichtig für Dienste mit langer Startphase (JVM, komplexe Initialisierung).

Healthcheck in Docker Compose

services:
  app:
    image: myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 30s

Alternativ als Shell-String:

healthcheck:
  test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]

CMD führt den Befehl direkt aus. CMD-SHELL führt ihn in /bin/sh -c aus — nötig für Shell-Operatoren wie ||.

Praxisbeispiele pro Technologie

PostgreSQL:

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
  interval: 10s
  timeout: 5s
  retries: 5
  start_period: 15s

Redis:

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

MySQL/MariaDB:

healthcheck:
  test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--silent"]
  interval: 10s
  timeout: 5s
  retries: 5
  start_period: 30s

HTTP-Endpunkt:

healthcheck:
  test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
  interval: 15s
  timeout: 5s
  retries: 3
  start_period: 20s

Die drei Health-States

| Status | Bedeutung |
|---|---|
| starting | Innerhalb der start_period, Fehlschläge zählen nicht |
| healthy | Letzter Check war erfolgreich |
| unhealthy | Zu viele aufeinanderfolgende Fehlschläge |

docker ps   # STATUS-Spalte zeigt (healthy) oder (unhealthy)

Warum Healthchecks mehr als nice-to-have sind

1. depends_on condition:

services:
  app:
    depends_on:
      db:
        condition: service_healthy   # Funktioniert nur mit Healthcheck

2. Docker Swarm — automatischer Neustart:
Swarm ersetzt unhealthy Container automatisch durch neue Instanzen.

3. Load-Balancer:
Traefik und andere Router entfernen unhealthy Container automatisch aus der Rotation.

4. Monitoring:

docker events --filter event=health_status

Healthcheck deaktivieren

Für Container, bei denen ein Check keinen Sinn ergibt:

healthcheck:
  disable: true

Oder im Dockerfile eines Basis-Images überschreiben:

HEALTHCHECK NONE

Health-Status in Skripten

# Warten bis Container healthy
while [ "$(docker inspect --format='{{.State.Health.Status}}' myapp)" != "healthy" ]; do
    sleep 2
done

# Health-Status ausgeben
docker inspect --format='{{.State.Health.Status}}' myapp

# Letzter Healthcheck-Output
docker inspect --format='{{(index .State.Health.Log 0).Output}}' myapp

Ein sorgfältig definierter Healthcheck macht aus einem Container, der irgendwie läuft, einen Dienst, dessen Zustand das System kennt und auf den es verlässlich reagieren kann.