Neu veröffentlicht: E-Commerce mit Power Pages, Stripe & Analytics

· David Göschel · DevOps  · 6 minuten Lesezeit

Observability für meinen Docker Compose Stack mit Bull Board und Dozzle

Ich wollte den Weg von der Extension bis zur Speicherung sichtbar machen. Mit Bull Board und Dozzle habe ich Queue Status und Container Logs direkt im Browser und kann Fehler jetzt viel schneller einordnen.

Ich wollte den Weg von der Extension bis zur Speicherung sichtbar machen. Mit Bull Board und Dozzle habe ich Queue Status und Container Logs direkt im Browser und kann Fehler jetzt viel schneller einordnen.

Inhalt

Der Ausgangspunkt

Ich hatte bereits einen funktionierenden Ingest Pfad. Die Extension schickt einen Capture Request, das Backend legt einen Job in Redis ab, ein Worker verarbeitet ihn später und Qdrant speichert das Ergebnis.

Das Problem war nicht der Ablauf selbst. Das Problem war die Sichtbarkeit. Wenn irgendwo zwischen POST /ingest, Redis, Worker und Qdrant etwas schiefging, sah ich nur das Symptom. Ich musste Logs zusammensuchen und den Queue Zustand indirekt ableiten. Genau da entsteht eine Blackbox.

Die Entscheidung

Ich habe mich bewusst für eine kleine Observability Schicht entschieden statt für eine große Monitoring Plattform. Die zwei Bausteine sind Bull Board für die Queue und Dozzle für die Logs.

Bull Board zeigt mir, ob Jobs angenommen werden, ob sie warten, aktiv sind, fehlschlagen oder fertig sind. Dozzle zeigt mir die Container Logs im Browser. Damit decke ich genau die Stellen ab, an denen ich im Alltag wirklich suche.

Ich habe OpenTelemetry und Jaeger bewusst zurückgestellt. Das wäre für End to End Tracing interessant, würde aber sofort mehr Instrumentierung im Backend, im Worker und später auch an weiteren Stellen bedeuten. Für diesen Schritt wollte ich zuerst Transparenz mit wenig Bewegung im System.

Warum Bull Board ein eigener Container ist

Ich hätte Bull Board auch direkt im Backend einhängen können. Ich habe mich dagegen entschieden, weil ich die Verantwortung trennen wollte.

Ein eigener Container hat für mich drei Vorteile. Erstens kann ich ihn unabhängig starten, neu starten oder austauschen. Zweitens bleibt das Backend schlank und konzentriert sich weiter auf die API. Drittens sehe ich Queue Daten getrennt von der Geschäftslogik und kann schneller debuggen, wenn ein Job hängen bleibt.

Bull Board hängt deshalb an derselben Redis Queue wie der Worker, läuft aber als eigene kleine Anwendung hinter Traefik. Lokal ist es direkt erreichbar, in Produktion ist es zusätzlich per IP Whitelist geschützt.

Warum Dozzle reicht

Bei Logs wollte ich keinen schweren Stack aufbauen. Für den aktuellen Stand reicht mir ein Browserfenster, in dem ich die Container Logs in Echtzeit sehe.

Dozzle hat dafür fast keine Betriebskosten. Es braucht keine eigene Datenbank, keine Retention Logik und keine zusätzliche Indexierung. Ich mounte nur den Docker Socket read only und kann dann sofort zwischen Backend, Worker, Traefik und den anderen Diensten wechseln.

Das ist vor allem im Debugging Alltag hilfreich. Wenn ein Capture hängen bleibt, sehe ich Queue Eintrag und Log Meldungen nebeneinander. Ich muss nicht erst per SSH auf eine VM, um mit docker logs zu arbeiten.

Was ich in der Infrastruktur geändert habe

Ich habe die Observability Schicht so eingebaut, dass lokale Entwicklung und Produktion möglichst gleich bleiben.

bull-board:
  build: ./bull-board
  networks:
    - traefik_net
    - internal_net
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.bull-board.rule=Host(`bull.localhost`)"

dozzle:
  image: amir20/dozzle:v8
  networks:
    - traefik_net
  labels:
    - "traefik.enable=true"
    - "traefik.http.routers.dozzle.rule=Host(`logs.localhost`)"

In Produktion laufen beide Dienste weiter über Traefik, aber nur über eine erlaubte IP Liste. So bleibt die Architektur gleich, nur der Zugriff wird enger kontrolliert.

Was sich dadurch allgemein verbessert hat

Die wichtigste Verbesserung ist nicht das Dashboard selbst. Die eigentliche Verbesserung ist, dass ich jetzt einen nachvollziehbaren Pfad habe.

Ich kann sehen, ob ein Job überhaupt in Redis angekommen ist. Ich kann sehen, ob ein Worker ihn angenommen hat. Ich kann die Logs dazu prüfen. Ich kann das Verhalten lokal und in Produktion auf dieselbe Weise nachvollziehen.

Dadurch sinkt die Zeit bis zur Ursache deutlich. Ich suche nicht mehr blind in mehreren Containern, sondern arbeite entlang desselben Flows, den die Daten auch nehmen.

Für mich ist das die richtige Art von Observability für diesen Stand des Projekts. Nicht maximal komplex, sondern genau so sichtbar, dass ich Fehler schneller finde und neue Änderungen sicherer einbauen kann.

Bull Board und Dozzle im gleichen Traefik Stack

Die Grafik zeigt den gleichen Stack, in den ich Bull Board und Dozzle eingebaut habe. Der Punkt ist nicht nur ein neues Tool, sondern ein klarer Weg von der Extension bis zur Speicherung, den ich lokal und in Produktion gleich bedienen kann.


Alle Artikel der Serie

  1. Vision und Systemübersicht: Chrome Extension, RAG-Architektur, Projekthintergrund: Artikel lesen
  2. RAG-System Aufbau: Qdrant, Embeddings, Cosine-Ähnlichkeit in TypeScript: Artikel lesen
  3. AI Provider Abstraktion: Ollama vs. OpenAI, Interface-Design, kein Vendor-Lock-in: Artikel lesen
  4. Chrome Extension MV3: Drei isolierte Laufzeitkontexte, Message Passing, Strategy Pattern: Artikel lesen
  5. Docker Compose Strategie: Override-Pattern, von lokal zu Azure: Artikel lesen
  6. Ollama lokal vs. Docker: Die Entscheidung und ihre Konsequenzen: Artikel lesen
  7. Ollama Auto-Pull Entrypoint: Automatisiertes Modell-Setup beim Container-Start: Artikel lesen
  8. tsconfig und Vite: Node16 vs. bundler, warum Vite eigene Regeln hat: Artikel lesen
  9. Instagram Caption mit MutationObserver vollständig laden: Artikel lesen
  10. Chrome Extension Foundation mit Health-Dot und Retry-Queue: Artikel lesen
  11. Phase 2 Features: Shadow DOM Overlay, Tailwind v4, Duplicate Detection: Artikel lesen
  12. Race Condition bei der Plattformerkennung: Wie ein UI-Event die Instagram-Erkennung bricht: Artikel lesen
  13. PostId-Extraktion in zwei Instagram-Layouts: querySelector vs. Ancestor-Traversal: Artikel lesen
  14. Instagram Karussell vollständig erfassen mit MutationObserver: Lazy-Loading, Observer-before-click, Timeout-Fallback: Artikel lesen
  15. Notiz und Tags beim Screenshot-Speichern: Artikel lesen
  16. Instagram Tastatur-Shortcuts blockieren Chrome Extension Eingaben: Artikel lesen
  17. Lowercase-Normalisierung und Duplikat-Erkennung im Tag-Input: Artikel lesen
  18. Zitadel Login V2 in Docker Compose: drei versteckte Fehler: Artikel lesen
  19. PKCE OAuth in einer Chrome MV3 Extension: Artikel lesen
  20. React Frontend mit react-oidc-context und Zitadel: Artikel lesen
  21. Vite Build-Time-Umgebungsvariablen in Docker: Artikel lesen
  22. Event-Driven Ingestion mit BullMQ und Redis: Artikel lesen
  23. MinIO statt Azurite: S3-kompatible Objektspeicherung lokal und auf Hetzner: Artikel lesen
  24. access_token, id_token und der Userinfo-Endpoint: was wohin gehört: Artikel lesen
  25. Qdrant Multi-Tenancy: Pro Nutzer eine eigene Collection: Artikel lesen
  26. Wenn Backend und Frontend unterschiedliche Typen kennen: Artikel lesen
  27. Zitadel Bootstrap entfernt: Host-Header-Bug und manuelles Setup: Artikel lesen
  28. Backend Code Review: sechs Probleme vor dem Launch behoben: Artikel lesen
  29. Traefik statt NGINX: Reverse Proxy für einen wachsenden Docker-Compose-Stack: Artikel lesen
  30. Zweischichtiges Rate Limiting: Traefik und express-rate-limit mit Redis: Artikel lesen
  31. DSGVO Art. 17 korrekt implementieren: Promise.allSettled und Export-Batching: Artikel lesen
  32. Embedding-Modell-Lock-in: Warum mxbai-embed-large eine Produktionsentscheidung für immer ist: Artikel lesen
  33. Docker Volumes in Produktion: Named Volumes, Bind Mounts und der Hetzner-Volume-Trick: Artikel lesen
  34. Zwei Sicherheitslücken vor dem Launch: Redis ohne Auth und ein offener Qdrant-Admin-Port: Artikel lesen
  35. Traefik als einziger Einstiegspunkt im Docker Compose Stack: Artikel lesen
  36. Zitadel hinter Traefik richtig verdrahten mit Issuer, JWKS und Login V2: Artikel lesen
  37. Frontend reparieren wenn der nginx Healthcheck an localhost scheitert: Artikel lesen
  38. Observability für meinen Docker Compose Stack mit Bull Board und Dozzle: (dieser Artikel)
  39. Qdrant Dashboard sicher öffnen mit lokalem Traefik und SSH Tunnel: Artikel lesen
  40. Diagnose: Warum mein Chunking trotz Tokenisierung noch scheiterte: Artikel lesen
  41. Entscheidung: Warum ich den Chunk auf 1500 Tokens gesetzt habe: Artikel lesen
  42. Implementierung: Wie ich den Embedding Workflow in mehrere saubere Schritte zerlegt habe: Artikel lesen
  43. Validierung: Wie ich Chunking, Speicherung und Suche wieder zusammenbringe: Artikel lesen

Du baust gerade einen ähnlichen Stack und fragst dich, wie du Queue Zustand und Logs sauber sichtbar machst? Lass uns das gemeinsam einschätzen.

Zurück zum Blog

Ähnliche Beiträge

Alle Beiträge ansehen