Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Monitoring 21.09.2026 · 21 min Lesezeit

OpenObserve mit Docker Compose betreiben: Logs, Metriken und Traces auf einem Server

OpenObserve bündelt Logs, Metriken und Traces in einer einzigen, in Rust geschriebenen Anwendung und läuft als einzelner Container. Diese Anleitung zeigt eine getestete compose.yaml, den ersten Log-Eintrag per HTTP-API, die Abfrage per SQL, Backup und Deinstallation. Zwei Stolpersteine aus dem eigenen Test sind ausführlich dokumentiert, darunter ein Zeitfenster-Fehler bei der Suche.

Illustration zur Anleitung: OpenObserve mit Docker betreiben, mit Karten für Logs, Metriken und Traces sowie einem abstrakten Dashboard KI-generiert

Wer mehrere Server, Container und Anwendungen betreibt, kennt das Problem: Logdateien liegen verstreut auf einzelnen Maschinen, Metriken stecken in einem separaten System und Traces existieren, wenn überhaupt, in einem dritten Werkzeug. Für ein kleines oder mittleres Unternehmen ist ein vollständiger Observability-Stack aus mehreren Komponenten oft zu aufwendig im Betrieb, und kommerzielle Cloud-Dienste werden mit steigendem Datenvolumen schnell teuer. OpenObserve tritt genau in diese Lücke: Die Plattform fasst Logs, Metriken und Traces in einer einzigen Anwendung zusammen, wird als ein einziges Programm ausgeliefert und lässt sich auf einem kleinen Server als einzelner Container starten.

Diese Anleitung führt durch den vollständigen Weg mit Docker Compose. Sie enthält eine compose.yaml, die genau so getestet wurde, eine Erklärung jeder relevanten Umgebungsvariablen, den ersten echten Log-Eintrag per HTTP-Schnittstelle samt der tatsächlich zurückgegebenen Antwort, die Abfrage der Daten per SQL, den Umgang mit persistenten Daten, den Weg zu einer abgesicherten Netzwerkfreigabe, Backup und Update sowie eine saubere Deinstallation. Zwei Fehler, die im Test real aufgetreten sind, werden ausführlich behandelt, weil beide leicht zu falschen Schlüssen verleiten. Alles, was nicht selbst nachgestellt wurde, ist im Text ausdrücklich als dokumentiert, aber nicht getestet gekennzeichnet.

Wofür sich OpenObserve eignet und wo die Grenzen liegen

OpenObserve ist laut Projektbeschreibung eine quelloffene Alternative zu kommerziellen Observability-Diensten für Logs, Metriken, Traces und Frontend-Monitoring. Die Anwendung ist in Rust geschrieben, speichert Daten im spaltenorientierten Parquet-Format, ist auf Objektspeicher ausgelegt, folgt dem OpenTelemetry-Standard und lässt sich per SQL sowie per PromQL abfragen. Der Betrieb als einzelnes Programm ohne zusätzliche Datenbank ist ausdrücklich vorgesehen. Das Repository liegt unter github.com/openobserve/openobserve und steht unter der AGPL-3.0. Abgerufen am 21.09.2026 wies das Repository 22.045 Sterne aus, der letzte Push datierte auf den 20.09.2026, das Projekt war nicht archiviert, und das zu diesem Zeitpunkt aktuelle Release war v1.0.3 vom 18.09.2026. Diese Zahlen stammen aus dem GitHub-Repository zum genannten Abrufdatum und sind eine Momentaufnahme, keine Trendaussage.

Gut geeignet ist OpenObserve für Teams, die einen zentralen Sammelpunkt für Logs aus mehreren Hosts suchen, ohne drei Systeme betreuen zu müssen. Der Einstieg ist niedrig, weil ein Container genügt, und die Abfragesprache SQL ist vielen Administratoren bereits vertraut. Wer Logs bisher per journalctl oder docker logs einzeln auf jedem Host liest, gewinnt hier viel.

Es gibt aber klare Grenzen. Ein einzelner Container ist kein hochverfügbares System. Fällt der Host aus, ist auch die Auswertung weg, und das ist ausgerechnet im Störungsfall unpraktisch. Die Projektdokumentation zum Hochverfügbarkeitsbetrieb sieht für diesen Fall einen Kubernetes-Cluster mit Helm, einen Objektspeicher und eine PostgreSQL- oder MySQL-Metadatenbank vor; lokaler Plattenspeicher wird in diesem Modus nicht unterstützt. Das ist deutlich mehr Aufwand als die hier beschriebene Einzelinstanz. Ebenfalls zu bedenken: OpenObserve ersetzt keine klassische Infrastrukturüberwachung mit aktiven Prüfungen. Wer wissen will, ob ein Switch-Port ausgefallen ist oder ein Zertifikat abläuft, braucht weiterhin ein Werkzeug, das aktiv prüft, statt nur passiv einzusammeln.

Zur Abgrenzung gegenüber verwandten Lösungen, ohne diese abzuwerten: Ein Prometheus-Stack ist auf Metriken und Alarmierung spezialisiert und dort sehr stark, deckt Logs und Traces aber nicht von sich aus ab. SigNoz verfolgt einen ähnlichen Ansatz wie OpenObserve, setzt intern jedoch auf mehrere Dienste und eine separate Datenbank, was mehr Komponenten im Betrieb bedeutet, dafür aber auch andere Skalierungsmöglichkeiten eröffnet. Netzwerküberwachung mit Geräteerkennung ist wieder ein eigenes Feld. Die sinnvolle Frage lautet deshalb nicht, welches Werkzeug das beste ist, sondern welches Signal im eigenen Betrieb gerade fehlt. Fehlen zentrale Logs, ist OpenObserve ein sehr direkter Weg dorthin.

Voraussetzungen und Ressourcenbedarf

Benötigt wird ein Linux-Host mit installiertem Docker und dem Compose-Plugin. Die in dieser Anleitung verwendeten Befehle setzen die moderne Schreibweise docker compose voraus, also das Compose-Plugin und nicht das alte separate Programm docker-compose. Die Version lässt sich so prüfen:

# Docker-Version anzeigen
docker --version

# Compose-Plugin prüfen, muss eine Version ausgeben
docker compose version

Zum Ressourcenbedarf sind die folgenden Werte Erfahrungswerte aus dem eigenen Test und keine offizielle Mindestanforderung. Das im Test verwendete Image public.ecr.aws/zinclabs/openobserve:v1.0.3 ist rund 150 MB groß. Der Start auf einem kleinen Server lief ohne Anpassungen durch. Für eine Einzelinstanz, die Logs einiger weniger Hosts aufnimmt, sind zwei CPU-Kerne und 2 GB Arbeitsspeicher ein realistischer Startpunkt; bei höherem Datenaufkommen ist Arbeitsspeicher die Größe, die zuerst knapp wird, weil Abfragen über größere Zeiträume Daten im Speicher verarbeiten.

Beim Plattenplatz gibt es keine pauschale Antwort, weil er direkt vom eingespeisten Volumen abhängt. Planen Sie das Volume großzügig und beobachten Sie das Wachstum in den ersten Wochen. Die Dokumentation zu den Umgebungsvariablen nennt für die Aufbewahrungsdauer die Variable ZO_COMPACT_DATA_RETENTION_DAYS mit einem Standardwert von 3650 Tagen, was zehn Jahren entspricht; der zulässige Mindestwert ist 3. Ohne Anpassung wird also praktisch nichts automatisch gelöscht. Wer Logs nur einige Wochen benötigt, sollte diesen Wert bewusst setzen, statt später überrascht zu werden.

Zur Plattformunterstützung: Getestet wurde ausschließlich auf einem Linux-Host mit x86-64-Architektur. Das Projekt bietet laut Dokumentation daneben Binärdateien für Windows sowie für Linux und macOS und beschreibt zusätzlich eine Installation unter Kubernetes. Ob das Container-Image auf ARM-Systemen wie einem Raspberry Pi läuft, wurde hier nicht geprüft und sollte vor einem Einsatz dort selbst verifiziert werden.

Die compose.yaml im Detail

Die folgende Datei ist die Grundlage. Der markierte Abschnitt mit den Healthcheck-Angaben ist eine sinnvolle Ergänzung, die über den eigentlichen Test hinausgeht und entsprechend gekennzeichnet ist. Alles andere entspricht der getesteten Konfiguration.

services:
  openobserve:
    # Feste Version statt latest, damit ein Neustart nicht ungeplant aktualisiert
    image: public.ecr.aws/zinclabs/openobserve:v1.0.3
    container_name: openobserve
    # Container startet nach Reboot oder Absturz automatisch neu
    restart: unless-stopped
    environment:
      # Zugangsdaten des Administrators, aus der .env-Datei gelesen
      ZO_ROOT_USER_EMAIL: ${ZO_ROOT_USER_EMAIL}
      ZO_ROOT_USER_PASSWORD: ${ZO_ROOT_USER_PASSWORD}
      # Ablageort der Daten im Container, passend zum Volume unten
      ZO_DATA_DIR: /data
      # Anonyme Telemetrie an das Projekt abschalten
      ZO_TELEMETRY: "false"
    volumes:
      # Benanntes Volume, damit die Daten einen Neustart ueberleben
      - openobserve_data:/data
    ports:
      # Nur auf localhost binden, Zugriff von aussen laeuft ueber einen Reverse Proxy
      - "127.0.0.1:5080:5080"
    # Ergaenzung, im Test nicht mitgeprueft: automatische Zustandspruefung
    healthcheck:
      test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:5080/healthz || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s

volumes:
  openobserve_data:

Die einzelnen Bestandteile im Detail:

  • image verweist auf das offizielle Container-Image im Registry-Pfad public.ecr.aws/zinclabs/openobserve. Der angehängte Tag v1.0.3 ist bewusst eine feste Version. Mit latest würde ein späteres docker compose pull unbemerkt eine andere Version ziehen, und genau das will man in der Produktion nicht.
  • container_name vergibt einen festen Namen. Das erleichtert Befehle wie docker logs openobserve, ist aber optional. Wer mehrere Instanzen parallel fährt, sollte die Zeile weglassen.
  • restart: unless-stopped sorgt dafür, dass der Container nach einem Neustart des Hosts wieder hochkommt, aber nicht, wenn er zuvor ausdrücklich manuell gestoppt wurde.
  • ZO_ROOT_USER_EMAIL und ZO_ROOT_USER_PASSWORD legen das Administratorkonto an. Laut Dokumentation werden diese Werte nur beim ersten Start benötigt, um den Benutzer anzulegen; bei späteren Starts sind sie nicht mehr erforderlich. In der Praxis schadet es nicht, sie stehen zu lassen. Die E-Mail-Adresse ist zugleich der Anmeldename.
  • ZO_DATA_DIR bestimmt, wohin die Anwendung ihre Daten schreibt. Laut Dokumentation liegt der Standard bei einem Unterverzeichnis data im Arbeitsverzeichnis. Hier wird ausdrücklich /data gesetzt, damit der Pfad exakt zum eingehängten Volume passt. Unterhalb dieses Verzeichnisses legt OpenObserve laut der Variablenreferenz getrennte Bereiche für die Metadatenbank, das Write-Ahead-Log und die Streams an.
  • ZO_TELEMETRY steht laut Dokumentation standardmäßig auf true und sendet anonyme Nutzungsdaten. Der Wert false schaltet das ab. Der Wert gehört in Anführungszeichen, weil YAML sonst einen Wahrheitswert daraus macht, während die Anwendung eine Zeichenkette erwartet.
  • volumes bindet ein benanntes Docker-Volume auf /data. Ein benanntes Volume ist hier einem Verzeichnis-Mount vorzuziehen, weil es unabhängig von den Rechten und der Benutzerkennung auf dem Host funktioniert.
  • ports mit der Angabe 127.0.0.1:5080:5080 ist der wichtigste Sicherheitsaspekt dieser Datei. Ohne das vorangestellte 127.0.0.1 wäre die Oberfläche unverschlüsselt aus dem gesamten Netz erreichbar. Der Standardport 5080 entspricht dem dokumentierten Standardwert von ZO_HTTP_PORT.
  • healthcheck ist die erwähnte Ergänzung. Sie fragt den Gesundheitsendpunkt ab und markiert den Container als fehlerhaft, wenn er nicht mehr antwortet. Dieser Block wurde im Test nicht mitgeprüft; falls wget im Image nicht vorhanden ist, schlägt er dauerhaft fehl und sollte dann entfernt oder angepasst werden.

Eine .env-Datei für die Zugangsdaten

Das Administratorpasswort hat in der compose.yaml nichts verloren. Diese Datei landet erfahrungsgemäß irgendwann in einer Versionsverwaltung, wird in einem Ticket zitiert oder an einen Kollegen weitergereicht. Compose liest Variablen automatisch aus einer Datei namens .env im selben Verzeichnis, sodass die Trennung ohne Zusatzaufwand funktioniert.

# .env  -  Platzhalter, vor dem Einsatz unbedingt ersetzen
ZO_ROOT_USER_EMAIL=admin@beispiel.local
ZO_ROOT_USER_PASSWORD=BitteHierEinEigenesLangesPasswortEintragen

Beide Werte sind ausdrücklich Platzhalter. Verwenden Sie ein eigenes, langes und zufälliges Passwort, idealerweise aus einem Passwortmanager. Ein Passwort, das dieselbe Zeichenfolge wie im Beispiel enthält, ist innerhalb von Minuten kompromittiert, sobald der Dienst irgendwann doch erreichbar wird.

Anschließend sollte die Datei so berechtigt werden, dass nur der Eigentümer sie lesen kann:

# Nur der Besitzer darf lesen und schreiben
chmod 600 .env

# Ergebnis kontrollieren, erwartet wird -rw-------
ls -l .env

Wer das Verzeichnis mit Git verwaltet, trägt .env zusätzlich in die Datei .gitignore ein. Ein versehentlich eingecheckter Zugangsdatensatz lässt sich aus der Historie nur mit erheblichem Aufwand wieder entfernen, und bis dahin gilt er als offengelegt.

Installation und erster Start

Legen Sie ein eigenes Verzeichnis für den Stack an. Ein klar benanntes Verzeichnis pro Dienst zahlt sich spätestens beim Backup aus.

# Verzeichnis anlegen und hineinwechseln
mkdir -p /opt/openobserve
cd /opt/openobserve

Legen Sie in diesem Verzeichnis die Datei compose.yaml mit dem oben gezeigten Inhalt und die Datei .env mit Ihren eigenen Zugangsdaten an. Danach folgt der eigentliche Start:

# Image laden und Container im Hintergrund starten
docker compose up -d

# Status der Dienste anzeigen
docker compose ps

# Startmeldungen der Anwendung ansehen
docker compose logs --tail 50 openobserve

Im Test lief docker compose up -d ohne Fehler durch, und docker compose ps meldete den Container im Zustand Up. Der erste Start dauert einen Moment länger, weil das Image geladen und die interne Datenablage angelegt wird. Falls der Container sofort wieder beendet wird, liefert die Logausgabe in aller Regel den Grund; typische Ursachen stehen weiter unten im Fehlerteil.

Funktionsprüfung und erster Log-Eintrag

Die erste Prüfung gilt dem Gesundheitsendpunkt. Der Aufruf ist unauthentifiziert möglich und beantwortet die Frage, ob die Anwendung überhaupt läuft:

# Gesundheitsendpunkt abfragen
curl -s http://127.0.0.1:5080/healthz

Im Test lieferte dieser Aufruf die Antwort {"status":"ok"} mit dem HTTP-Status 200. Anschließend die Weboberfläche, die im Test unter dem Pfad /web/ ebenfalls mit HTTP 200 antwortete:

# Nur den HTTP-Statuscode der Oberflaeche ausgeben
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:5080/web/

Läuft der Server nicht auf dem eigenen Arbeitsplatz, sondern auf einem entfernten Host, ist ein SSH-Tunnel der einfachste Weg zur Oberfläche, solange noch kein Reverse Proxy eingerichtet ist. Der folgende Befehl leitet den lokalen Port 5080 auf den Server weiter, danach ist die Oberfläche im Browser unter http://127.0.0.1:5080/web/ erreichbar:

# Lokalen Port 5080 auf den entfernten Host weiterleiten
ssh -L 5080:127.0.0.1:5080 benutzer@servername

Nun der erste echte Datensatz. OpenObserve nimmt Logs per HTTP entgegen. Der dokumentierte Endpunkt lautet POST /api/{organisation}/{stream}/_json und erwartet ein JSON-Array von Objekten. Die Standardorganisation heißt default, der Stream wird beim ersten Schreiben automatisch angelegt. Die Authentifizierung erfolgt per Basic-Auth mit der Root-Mail-Adresse und dem Root-Passwort.

# Zugangsdaten aus der .env-Datei in die Shell laden
set -a
. ./.env
set +a

# Einen Testdatensatz in den Stream testlogs schreiben
curl -s -u "$ZO_ROOT_USER_EMAIL:$ZO_ROOT_USER_PASSWORD" \
  -H "Content-Type: application/json" \
  -d '[{"level":"info","service":"testdienst","message":"Erster Eintrag"}]' \
  http://127.0.0.1:5080/api/default/testlogs/_json

Die im Test tatsächlich zurückgegebene Antwort lautete:

{"code":200,"status":[{"name":"testlogs","successful":1,"failed":0}]}

Entscheidend sind die Felder successful und failed. Ein Wert von 200 im Feld code bedeutet lediglich, dass die Anfrage angenommen wurde; ob die einzelnen Datensätze verarbeitet wurden, steht in der Liste darunter. Bei einer Sammelanfrage mit vielen Einträgen kann failed durchaus größer als null sein, während der Statuscode weiterhin 200 lautet.

Danach sollte der neue Stream in der Übersicht auftauchen. Im Test war das der Fall:

# Vorhandene Streams der Organisation default auflisten
curl -s -u "$ZO_ROOT_USER_EMAIL:$ZO_ROOT_USER_PASSWORD" \
  http://127.0.0.1:5080/api/default/streams

Nun die Abfrage. Sie erfolgt per POST auf /api/default/_search und erwartet ein Zeitfenster. Dieses Zeitfenster wird in Mikrosekunden angegeben, nicht in Sekunden und nicht in Millisekunden. Das ist der Punkt, an dem die meisten ersten Versuche scheitern. Die folgenden zwei Shell-Variablen erzeugen ein Fenster von einer Stunde bis jetzt:

# Aktueller Zeitpunkt in Mikrosekunden
NOW=$(date +%s000000)

# Zeitpunkt vor einer Stunde in Mikrosekunden
AGO=$(( $(date -d '1 hour ago' +%s)000000 ))

# Die letzten fuenf Eintraege aus dem Stream testlogs abfragen
curl -s -u "$ZO_ROOT_USER_EMAIL:$ZO_ROOT_USER_PASSWORD" \
  -H "Content-Type: application/json" \
  -d "{\"query\":{\"sql\":\"SELECT * FROM testlogs\",\"start_time\":$AGO,\"end_time\":$NOW,\"from\":0,\"size\":5}}" \
  http://127.0.0.1:5080/api/default/_search

Im Test kam der zuvor geschriebene Eintrag korrekt zurück, mit total: 1 und einem Feld _timestamp, das den Zeitstempel ebenfalls in Mikrosekunden enthält. Wer diesen Wert in der eigenen Auswertung weiterverarbeitet, muss ihn also durch eine Million teilen, um auf gewöhnliche Unix-Sekunden zu kommen.

Persistente Daten, Rechte und was beim Neustart passiert

Sämtliche Nutzdaten liegen im benannten Volume openobserve_data, das im Container unter /data eingehängt ist. Dazu gehören die eingespeisten Streams, die interne Metadatenbank, Benutzerkonten und alles, was später in der Oberfläche angelegt wird. Das Volume existiert unabhängig vom Container. Ein docker compose down entfernt den Container, das Volume bleibt bestehen, und ein anschließendes docker compose up -d findet alle Daten wieder vor. Das wurde im Test durch den normalen Betrieb bestätigt.

# Vorhandene Volumes anzeigen
docker volume ls

# Details zum Volume inklusive Ablageort auf dem Host anzeigen
docker volume inspect openobserve_data

Zu den Rechten: Weil ein benanntes Volume verwendet wird, verwaltet Docker den Besitzer selbst, und es sind keine manuellen Anpassungen nötig. Das ist der wesentliche Vorteil gegenüber einem Verzeichnis-Mount vom Host, bei dem die Benutzerkennung im Container zur Kennung auf dem Host passen muss. Wer dennoch ein Hostverzeichnis einhängen möchte, etwa weil das Backup-Konzept es verlangt, muss die Schreibrechte für die Kennung sicherstellen, unter der die Anwendung im Container läuft; andernfalls beendet sich der Container beim Start mit einem Schreibfehler. Dieser Fall wurde nicht selbst getestet.

Nach einem Neustart des Hosts sorgt restart: unless-stopped dafür, dass der Container automatisch wieder anläuft, sofern der Docker-Dienst selbst beim Systemstart aktiviert ist. Das lässt sich mit systemctl is-enabled docker prüfen.

Sichere Netzwerkfreigabe und Reverse Proxy mit TLS

Die Portangabe im Test lautete bewusst 127.0.0.1:5080:5080 und nicht 5080:5080. Der Unterschied ist erheblich. Ohne die vorangestellte Adresse bindet Docker den Port an alle Schnittstellen des Hosts, und zwar an der Firewall des Betriebssystems vorbei, weil Docker seine Weiterleitungsregeln direkt in die Paketfilterketten einträgt. Eine vermeintlich schützende Regel in der Host-Firewall greift dann unter Umständen nicht. Das Ergebnis wäre eine unverschlüsselte Anmeldemaske im offenen Netz, über die sich jeder mit den Root-Zugangsdaten Zugang zu allen gesammelten Logs verschaffen könnte. Logs enthalten regelmäßig Benutzernamen, interne Hostnamen, Pfade und gelegentlich auch Daten, die dort nie hätten landen dürfen. Die Bindung an 127.0.0.1 ist deshalb keine Vorsichtsmaßnahme, sondern Pflicht.

Für den Zugriff von außen ist ein vorgelagerter Reverse Proxy mit TLS der richtige Weg. Der Proxy nimmt die HTTPS-Verbindung entgegen, kümmert sich um das Zertifikat und leitet intern an 127.0.0.1:5080 weiter. Der folgende Abschnitt beschreibt den Ansatz auf Basis der Dokumentation und allgemeiner Betriebspraxis; er wurde in diesem Test nicht durchgespielt und ist entsprechend als nicht verifiziert zu behandeln.

  • Einen Reverse Proxy auf demselben Host betreiben, der auf Port 443 lauscht und Zertifikate automatisch bezieht.
  • Einen eigenen DNS-Namen für den Dienst vergeben und das Zertifikat auf diesen Namen ausstellen lassen.
  • Die Weiterleitung auf http://127.0.0.1:5080 konfigurieren und dabei die üblichen Weiterleitungs-Kopfzeilen für die ursprüngliche Adresse und das ursprüngliche Protokoll setzen.
  • Den Zugang zusätzlich einschränken, etwa auf das Firmennetz oder ein VPN. Ein Observability-System muss selten aus dem offenen Internet erreichbar sein.
  • Nach der Einrichtung ausdrücklich prüfen, dass der Dienst nicht zusätzlich noch direkt über Port 5080 von außen erreichbar ist.

Ein Punkt verdient dabei besondere Aufmerksamkeit: Wenn der Reverse Proxy selbst in einem Container läuft, ist 127.0.0.1 aus Sicht dieses Containers nicht der Host. In diesem Fall gehören beide Dienste in ein gemeinsames Docker-Netzwerk, und der Proxy spricht OpenObserve über den Dienstnamen an. Die Portfreigabe nach außen kann dann bei OpenObserve vollständig entfallen, was die sauberste Variante ist.

Backup und Wiederherstellung

Ein Backup muss zwei Dinge umfassen: die Konfiguration und die Daten. Die Konfiguration besteht aus der compose.yaml und der .env, also aus zwei kleinen Dateien im Stack-Verzeichnis. Beide gehören in die reguläre Dateisicherung, wobei die .env wegen des enthaltenen Passworts eine verschlüsselte Ablage verdient.

Die Daten liegen im Volume. Der folgende Weg sichert das Volume über einen kurzlebigen Hilfscontainer in ein Archiv. Der Container wird für diesen Zweck zum Zeitpunkt des Backups gestoppt, damit keine Schreibvorgänge mitten im Archiv landen. Dieser Ablauf wurde in diesem Test nicht durchgeführt und ist deshalb als dokumentierter, aber nicht verifizierter Weg zu verstehen; er sollte vor dem Produktiveinsatz einmal vollständig geprobt werden.

# Dienst vor der Sicherung sauber anhalten
docker compose stop

# Volume in ein tar-Archiv im aktuellen Verzeichnis sichern
docker run --rm \
  -v openobserve_data:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/openobserve-data.tar.gz -C /data .

# Dienst wieder starten
docker compose start

Die Wiederherstellung läuft in umgekehrter Richtung. Wichtig ist, dass das Zielvolume vorher existiert und leer ist, sonst vermischen sich alter und neuer Bestand:

# Dienst anhalten und Container entfernen, Volume bleibt bestehen
docker compose down

# Vorhandenes Volume entfernen und neu anlegen
docker volume rm openobserve_data
docker volume create openobserve_data

# Archiv in das leere Volume zurueckspielen
docker run --rm \
  -v openobserve_data:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/openobserve-data.tar.gz -C /data

# Dienst wieder starten
docker compose up -d

Ein Backup, das nie zurückgespielt wurde, ist kein Backup, sondern eine Hoffnung. Probieren Sie die Wiederherstellung einmal auf einem Testsystem aus, bevor Sie sich im Ernstfall darauf verlassen. Wer die Objektspeicher-Anbindung nutzt, hat eine andere Ausgangslage, weil die eigentlichen Daten dann nicht mehr lokal liegen; diese Betriebsart wurde hier nicht getestet.

Updates und die Grenzen eines Rollbacks

Der Grund für den festen Versions-Tag in der compose.yaml zeigt sich beim Update. Mit latest entscheidet der Zufallszeitpunkt des nächsten Neustarts darüber, welche Version läuft. Mit einem festen Tag entscheiden Sie das bewusst.

# Aktuell laufende Version im Container pruefen
docker compose images

# Nach dem Anpassen des Tags in der compose.yaml: neues Image laden
docker compose pull

# Container mit der neuen Version ersetzen
docker compose up -d

# Startmeldungen auf Migrationshinweise oder Fehler durchsehen
docker compose logs --tail 100 openobserve

Der Ablauf ist also: Backup erstellen, den Tag in der compose.yaml auf die gewünschte Version ändern, Image laden, Container ersetzen, Logs kontrollieren und anschließend den Gesundheitsendpunkt sowie eine Beispielabfrage prüfen. Vor einem Versionssprung lohnt ein Blick in die Veröffentlichungshinweise des Projekts, insbesondere bei einem Wechsel der Hauptversionsnummer.

Zum Rollback eine ehrliche Einordnung: Den Tag in der compose.yaml wieder auf die alte Version zu setzen, funktioniert technisch. Es gibt aber keine Garantie, dass die ältere Version mit einem Datenbestand umgehen kann, den eine neuere Version bereits migriert hat. Schema- oder Formatänderungen sind in solchen Systemen üblich und in aller Regel nur in eine Richtung vorgesehen. Der belastbare Rückweg ist deshalb nicht der alte Tag allein, sondern der alte Tag zusammen mit dem vor dem Update erstellten Backup. Wer das Backup überspringt, hat streng genommen kein Rollback, sondern nur einen Versuch.

Typische Fehler mit Diagnose und Lösung

Suche scheitert mit invalid time range

Dieser Fehler ist im Test real aufgetreten. Ein Aufruf von _search mit "start_time":0 und einem beliebig groß gewählten end_time wird nicht etwa als Abfrage über den gesamten Zeitraum verstanden, sondern mit folgender Antwort abgelehnt:

{"code":400,"message":"Error# [file_list] invalid time range"}

Die Ursache ist nicht die Abfrage selbst und auch nicht die SQL-Syntax, sondern das Zeitfenster. Die Grenzen müssen einen realistischen Bereich in Mikrosekunden beschreiben. Wer den Fehler auf die SQL-Anweisung schiebt und dort nach dem Problem sucht, verliert Zeit. Die Lösung besteht darin, die Grenzen sauber zu erzeugen, wie bereits im Abschnitt zur Funktionsprüfung gezeigt: NOW=$(date +%s000000) für den aktuellen Zeitpunkt und AGO=$(( $(date -d '1 hour ago' +%s)000000 )) für den Beginn des Fensters. Wenn eine Abfrage keine Treffer liefert, obwohl Daten vorhanden sein müssten, lohnt als erstes ein Blick darauf, ob das Zeitfenster versehentlich in Sekunden statt in Mikrosekunden angegeben wurde; ein um den Faktor eine Million verschobenes Fenster liegt schlicht in einer anderen Epoche.

Keine Shell im Container verfügbar

Ebenfalls im Test aufgetreten und für viele Administratoren überraschend: Der Versuch, sich zur Fehlersuche in den Container zu verbinden, schlägt fehl.

exec failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory

Das Image ist ein minimales Image ohne Shell und ohne die gewohnten Werkzeuge. Das ist kein Defekt, sondern gewollt, weil eine kleinere Angriffsfläche entsteht. Für die Praxis bedeutet es aber, dass der vertraute Reflex docker compose exec openobserve /bin/sh ins Leere läuft. Die Diagnose muss stattdessen von außen erfolgen: über docker compose logs für die Anwendungsmeldungen, über docker inspect für Konfiguration und Zustand und über die HTTP-Endpunkte für die Funktionsprüfung. Wer unbedingt in das Dateisystem des Containers schauen muss, kann Dateien mit docker cp herauskopieren oder das Volume wie beim Backup mit einem separaten Hilfscontainer einhängen.

Port bereits belegt

Ist Port 5080 auf dem Host bereits vergeben, verweigert Compose den Start mit einer Meldung über eine bereits verwendete Adresse. Dieses Fehlerbild wurde hier nicht eigens herbeigeführt und ist als allgemeine Docker-Erfahrung einzuordnen. Prüfen lässt es sich so:

# Belegung des Ports auf dem Host pruefen
ss -tlnp | grep 5080

Die Lösung ist entweder das Beenden des belegenden Dienstes oder ein anderer Host-Port in der compose.yaml, etwa "127.0.0.1:5081:5080". Ändern Sie dabei nur die linke Seite; der rechte Wert ist der Port innerhalb des Containers und muss zur Konfiguration der Anwendung passen.

Anmeldung schlägt fehl

Wenn die Anmeldung an der Oberfläche oder die Basic-Auth an der API abgewiesen wird, sind zwei Ursachen wahrscheinlich, beide nicht eigens getestet, aber aus der dokumentierten Funktionsweise gut ableitbar. Erstens kann das Passwort schlicht falsch sein, etwa weil Sonderzeichen in der Shell ausgewertet wurden statt wörtlich übergeben zu werden. Setzen Sie Werte in der .env nicht in Anführungszeichen, wenn Sie sie nicht benötigen, und prüfen Sie mit docker compose config, welche Werte Compose tatsächlich einsetzt. Zweitens gilt laut Dokumentation, dass die Root-Zugangsdaten nur beim ersten Start ausgewertet werden, um das Konto anzulegen. Wer das Passwort später in der .env ändert und einen bestehenden Datenbestand weiterverwendet, meldet sich deshalb weiterhin mit dem alten Passwort an. Der Wechsel gehört in diesem Fall in die Benutzerverwaltung der Oberfläche.

Container startet nicht oder beendet sich sofort

Beendet sich der Container direkt nach dem Start, ist die Logausgabe die erste Anlaufstelle. Häufige Ursachen sind fehlende Schreibrechte auf dem Datenverzeichnis, wenn statt eines benannten Volumes ein Hostverzeichnis eingehängt wurde, sowie Syntaxfehler in der compose.yaml, insbesondere bei der Einrückung.

# Vollstaendige Logausgabe ansehen
docker compose logs openobserve

# Zusammengesetzte Konfiguration pruefen, deckt YAML-Fehler und leere Variablen auf
docker compose config

Der Befehl docker compose config ist dabei besonders nützlich, weil er die Datei nach dem Einsetzen aller Variablen ausgibt. Bleibt dort ein Wert leer, fehlt die entsprechende Zeile in der .env oder die Datei liegt nicht im selben Verzeichnis.

Saubere Deinstallation mit Warnung vor Datenverlust

An dieser Stelle ist Genauigkeit wichtig, weil ein einzelner Parameter über den Verbleib aller gesammelten Daten entscheidet.

Der folgende Befehl stoppt und entfernt den Container und das zugehörige Netzwerk. Das Volume mit allen Daten bleibt dabei erhalten, und ein späteres docker compose up -d findet den alten Stand wieder vor:

# Container und Netzwerk entfernen, Daten bleiben erhalten
docker compose down

Der nächste Befehl entfernt zusätzlich die Volumes des Stacks. Damit werden alle eingespeisten Logs, sämtliche Metadaten, Benutzerkonten und alle in der Oberfläche angelegten Objekte endgültig gelöscht. Es gibt keine Rückfrage und keinen Papierkorb. Ohne ein zuvor erstelltes Backup ist dieser Vorgang nicht umkehrbar. Führen Sie ihn nur aus, wenn Sie den Datenbestand wirklich nicht mehr benötigen, und vergewissern Sie sich vorher, dass Sie sich im richtigen Verzeichnis befinden:

# ACHTUNG: loescht zusaetzlich alle Daten im Volume, unwiederbringlich
docker compose down -v

Zum vollständigen Aufräumen gehören anschließend noch das Image und das Stack-Verzeichnis. Auch hier gilt: Die .env enthält ein Passwort und sollte nicht achtlos liegen bleiben.

# Image entfernen
docker image rm public.ecr.aws/zinclabs/openobserve:v1.0.3

# Pruefen, ob das Volume wirklich verschwunden ist
docker volume ls | grep openobserve

Passende Anleitungen auf S-EDV

Quellen

OpenObserveDocker ComposeObservabilityLogsMonitoringSelfhostingTraces