Dieses Problem hat mich kürzlich mehr Zeit gekostet, als ich zugeben möchte – und die Ursache war so subtil wie frustrierend.
aibix
Das Symptom
Ein Docker-Container wird gestartet, der Dienst darin läuft korrekt und beantwortet Anfragen. Doch im Traefik-Dashboard taucht er schlicht nicht auf. Kein Router, kein Service, keine Fehlermeldung. Nichts.
Man prüft die Labels, die Netzwerkkonfiguration, die Docker-Socket-Verbindung – alles sieht korrekt aus. Und doch: Traefik weigert sich, den Container zu routen.
Die Ursache: Hardcodierte Healthchecks
Viele Docker-Images bringen einen eingebauten HEALTHCHECK mit. Im Dockerfile sieht das typischerweise so aus:
```dockerfile
HEALTHCHECK CMD [ "curl", "-f", "http://localhost:8080/health" ]
Das Problem entsteht, wenn der Dienst im Container auf einem anderen Port gestartet wird – etwa weil man --port 8000 als Argument übergibt oder eine Umgebungsvariable den Port ändert. Der Healthcheck prüft weiterhin localhost:8080, dort antwortet aber niemand. Docker markiert den Container daraufhin als unhealthy.
Und genau hier greift Traefik’s Docker-Provider: Container, die den Status unhealthy haben, werden stillschweigend aus dem Routing ausgeschlossen. Kein Fehler im Dashboard, keine Warnung im Standard-Log. Erst auf Loglevel debug erscheint die Meldung „Filtering unhealthy or starting container“ – und selbst die ist leicht zu übersehen.
Dieses Verhalten ist fest im Docker-Provider von Traefik verankert. Es gibt keine Konfigurationsoption, um es abzuschalten. Entsprechende Feature-Requests existieren seit Jahren (z.B. traefik/traefik#7842), wurden aber bislang nicht umgesetzt.
Die Fehlerkette im Detail
1. Der Container startet mit einem vom Standard abweichenden Port (z.B. 8000)
2. Der Dienst bindet sich an diesen Port und funktioniert einwandfrei
3. Docker’s Healthcheck prüft den im Image hartkodierten Port (z.B. 8080) – Verbindung abgelehnt
4. Docker setzt den Container-Status auf unhealthy
5. Traefik erkennt den Status und schließt den Container komplett vom Routing aus
6. Im Dashboard und in den Standard-Logs gibt es keinen Hinweis auf das Problem
Lösungen
Variante A: Internen Port beibehalten, extern mappen
Die einfachste und robusteste Lösung: Den Container-internen Port beim Standard belassen und Docker’s Port-Mapping nutzen, um den Dienst auf dem gewünschten Host-Port verfügbar zu machen.
```bash
docker run -d -p 3010:8080 mein-image:latest
Der Healthcheck funktioniert, Traefik sieht einen gesunden Container, und der Dienst ist extern auf Port 3010 erreichbar. In der Traefik-Konfiguration zeigt der Loadbalancer weiterhin auf den internen Port:
```yaml
labels:
- "traefik.http.services.mein-service.loadbalancer.server.port=8080"
Variante B: Healthcheck zur Laufzeit überschreiben
Wenn ein anderer interner Port zwingend erforderlich ist, kann der Healthcheck beim Start des Containers angepasst werden:
```bash
docker run --health-cmd "curl -f http://localhost:3010/health" mein-image:latest
Oder in docker-compose.yml:
```yaml
services:
mein-service:
image: mein-image:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3010/health"]
interval: 30s
timeout: 10s
retries: 3
Variante C: Healthcheck deaktivieren
Falls kein Healthcheck benötigt wird, lässt er sich komplett abschalten:
```bash
docker run --no-healthcheck mein-image:latest
```
Oder in docker-compose.yml:
```yaml
healthcheck:
test: ["NONE"]
Ohne definierten Healthcheck meldet Docker keinen Gesundheitsstatus, und Traefik hat keinen Grund, den Container zu filtern.
Fazit
Dieses Problem ist ein Paradebeispiel für eine Fehlerkette, bei der zwei an sich sinnvolle Mechanismen – Docker-Healthchecks und Traefik’s Container-Filterung – in Kombination zu schwer auffindbarem Fehlverhalten führen. Besonders tückisch ist die völlige Abwesenheit von Fehlermeldungen auf Standard-Loglevel.
Wer Traefik als Reverse-Proxy für Docker-Container einsetzt, sollte bei unerklärlichem Routing-Verhalten immer als Erstes den Health-Status der betroffenen Container prüfen:
```bash
docker inspect --format='{{.State.Health.Status}}' container-name
Zeigt dieser unhealthy, ist die Ursache mit hoher Wahrscheinlichkeit gefunden – auch wenn der Dienst selbst einwandfrei läuft.
-GF
Keine Produkte gefunden.