Health Checks en Zero-Downtime Deployments met Docker Compose
Implementeer robuuste health checks en rolling updates voor productie-omgevingen zonder downtime. Praktische voorbeelden met NGINX, PostgreSQL en applicatie-containers.
Jean-Pierre Broeders
Freelance DevOps Engineer
Health Checks en Zero-Downtime Deployments met Docker Compose
Een productie-omgeving draait 24/7. Containers kunnen crashen, databases kunnen vast lopen, en updates moeten gebeuren zonder dat gebruikers iets merken. Health checks en zero-downtime deployments vormen de basis voor betrouwbare systemen.
Waarom Health Checks Essentieel Zijn
Een container kan draaien zonder dat de applicatie binnen die container daadwerkelijk werkt. De database kan onbereikbaar zijn. De API kan timeout errors geven. Een simpele docker ps toont alleen of het proces actief is — niet of het gezond is.
Health checks detecteren dit soort problemen automatisch. Bij een falende health check kan de container opnieuw opstarten, of de load balancer stuurt traffic naar gezonde instances.
Health Check Configuratie
Een basale health check voor een web applicatie ziet er zo uit:
services:
web:
image: myapp:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Wat gebeurt er?
- Elke 30 seconden wordt de endpoint gecontroleerd
- De check mag maximaal 10 seconden duren
- Na 3 falende pogingen geldt de container als "unhealthy"
- De eerste 40 seconden worden gefaalde checks genegeerd (opstarttijd)
Voor databases werkt een andere aanpak beter:
services:
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
pg_isready controleert of PostgreSQL daadwerkelijk verbindingen accepteert. Dit is betrouwbaarder dan alleen checken of het proces draait.
Dependencies Tussen Services
Applicaties starten vaak te snel, voordat de database klaar is. Dit veroorzaakt crashes bij het opstarten. De depends_on optie combineert goed met health checks:
services:
web:
image: myapp:latest
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/ready"]
interval: 15s
timeout: 5s
retries: 3
postgres:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
De web applicatie start pas als PostgreSQL en Redis beide gezond zijn. Dit voorkomt race conditions en onnodige crashes.
Zero-Downtime Deployments
Een update zonder downtime vereist een rolling update strategie. Docker Compose ondersteunt dit niet standaard, maar er zijn twee praktische oplossingen.
Optie 1: Blue-Green met Proxy
Draai twee identieke stacks achter een load balancer. Update de ene terwijl de andere traffic afhandelt:
services:
web-blue:
image: myapp:v1
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
web-green:
image: myapp:v2
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
depends_on:
web-blue:
condition: service_healthy
web-green:
condition: service_healthy
NGINX routeert traffic naar de gezonde containers. Een simpele configuratie:
upstream backend {
server web-blue:8080 max_fails=3 fail_timeout=30s;
server web-green:8080 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503;
}
location /health {
access_log off;
return 200 "OK";
}
}
Bij een deployment wordt eerst web-green gestopt en vervangen door de nieuwe versie. NGINX routeert automatisch alles naar web-blue. Zodra web-green gezond is, wordt web-blue vervangen.
Optie 2: Rolling Update met Replicas
Voor grotere deployments werkt Docker Swarm beter. Een simpele migratie:
version: "3.8"
services:
web:
image: myapp:latest
deploy:
replicas: 4
update_config:
parallelism: 1
delay: 10s
order: start-first
rollback_config:
parallelism: 1
delay: 10s
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
De configuratie update één replica per keer met 10 seconden vertraging. De start-first optie start nieuwe containers voordat oude worden gestopt. Bij problemen rolt Swarm automatisch terug.
Deploy met: docker stack deploy -c docker-compose.yml myapp
Monitoring van Health Checks
Health checks zijn waardeloos zonder monitoring. Een simpele oplossing met een health check aggregator:
services:
healthcheck-monitor:
image: alpine:latest
command: |
sh -c '
while true; do
echo "=== Health Check Status ==="
docker ps --format "table {{.Names}}\t{{.Status}}"
sleep 60
done
'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
Voor productie is dit te basic. Betere oplossingen integreren met Prometheus of Grafana. Een voorbeeld met metrics export:
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
ports:
- "8081:8080"
cAdvisor exporteert container metrics inclusief health status naar Prometheus. Dit geeft realtime inzicht in de gezondheid van alle services.
Praktische Tips
Test health checks lokaal. Een falende health check in productie betekent downtime. Controleer of de endpoint snel genoeg reageert en betrouwbaar is:
docker compose up -d
docker inspect --format='{{.State.Health.Status}}' container_name
Maak onderscheid tussen liveness en readiness. Een liveness check detecteert crashes. Een readiness check bepaalt of de container traffic aan kan. Beide zijn belangrijk:
| Check Type | Doel | Actie bij falen |
|---|---|---|
| Liveness | Is de app gecrasht? | Container herstarten |
| Readiness | Kan de app traffic aan? | Geen nieuwe requests sturen |
Docker Compose ondersteunt alleen liveness checks. Voor readiness checks is een load balancer nodig die beide endpoints controleert.
Vermijd te agressieve timeouts. Een health check die elke 5 seconden draait kan de database overbelasten. Start met langzame intervallen en verscherp alleen als nodig.
Log gefaalde health checks. Dit helpt bij debugging:
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
Conclusie
Health checks en zero-downtime deployments zijn geen luxe. Ze vormen de basis voor betrouwbare productie-omgevingen. Start met simpele health checks op kritieke services. Voeg dependencies toe om race conditions te voorkomen. Implementeer een deployment strategie die downtime voorkomt.
Zonder deze fundamenten blijft een productie-omgeving kwetsbaar voor onverwachte crashes en downtime tijdens updates. Met de juiste configuratie draaien systemen stabiel en kunnen updates gebeuren zonder dat gebruikers het merken.
