Blog · 26. August 2025 · Aktualisiert am 7. September 2026 · 10 Min. Lesezeit

Kubernetes Logging mit Loki und Grafana

Mann blickt auf zwei Monitore voller Konsolenausgaben und Logzeilen in einem abgedunkelten Raum
Foto: Mikhail Nilov / Pexels

Kubernetes Logging mit Loki und Grafana bündelt die Container-Logs deines gesamten Clusters an einem Ort: Ein Log-Sammler liest sie auf jeder Node ein, Loki speichert sie schlank nach Labels sortiert, und du durchsuchst alles über Grafana mit einer eigenen Abfragesprache namens LogQL. Das ersetzt das Springen zwischen einzelnen kubectl logs-Aufrufen durch eine zentrale Suche über den ganzen Cluster, auch wenn ein Pod längst wieder verschwunden ist.

Der Loki-Stack unterscheidet sich bewusst von klassischen Logging-Lösungen. Loki indiziert nicht den kompletten Log-Text, sondern nur die Labels drumherum, dazu gleich mehr. Das macht den Betrieb günstiger und einfacher, verlangt dir dafür aber Disziplin bei der Wahl der Labels ab, sonst wird die Suche langsam statt schnell.

Ich betreibe produktionsreife Kubernetes-Cluster und setze Loki zusammen mit Grafana genau für dieses Logging in meinem eigenen Produktionscluster ein. Alle meine Beiträge zum Betrieb von Kubernetes-Clustern findest du gesammelt auf der Seite Kubernetes.

Warum Loki statt ELK für Kubernetes Logging

Der klassische Weg für zentrales Logging heißt ELK oder EFK: Elasticsearch, Logstash oder Fluentd, Kibana. Dabei landet jede Logzeile vollständig in einem invertierten Volltext-Index, jedes Wort wird durchsuchbar. Das ist mächtig, kostet aber Speicher und Rechenleistung, die mit der Log-Menge deines Clusters mitwächst, oft schneller als dir lieb ist.

Loki geht den umgekehrten Weg und orientiert sich an Prometheus, nur für Logs statt Metriken. Statt jedes Wort zu indizieren, merkt sich Loki nur die Kombination der Labels, unter denen eine Logzeile ankam, etwa Namespace, Anwendung und Pod. Der eigentliche Text landet komprimiert in Chunks, die du beim Abfragen erst nach der Auswahl der passenden Labels durchsuchst. Der Index bleibt dadurch klein, selbst wenn die Log-Menge über Monate wächst.

Loki Elasticsearch (ELK/EFK)
Was indiziert wird nur Labels wie Namespace, App, Pod der komplette Log-Text jeder Zeile
Speicherbedarf gering, komprimierte Chunks in Object Storage hoch, invertierter Volltext-Index
Abfragesprache LogQL, angelehnt an PromQL eigene Query-Syntax mit Volltextsuche
Betriebsaufwand wenige Komponenten, im Kleinen ein Binary Indexing, Sharding und Replikas selbst verwalten
Stärke viele Logs günstig durchsuchen, nach Labels eingrenzen freie Volltextsuche über beliebige Felder

Für dich heißt das ganz konkret: Beginnt deine Suche meistens mit einem Namespace, einer Anwendung oder einem Pod, und filterst du danach im Text nach einem Begriff, passt Loki gut zu deinem Alltag. Willst du dagegen völlig frei über beliebige Felder suchen, etwa quer über alle Anwendungen nach einer Kundennummer, ohne vorher einzugrenzen, ist ein Volltext-Index wie Elasticsearch im Vorteil. Ich nutze Loki, weil meine Abfragen fast immer bei einem Namespace oder einer Anwendung beginnen.

Loki-Architektur in fünf Sätzen

Loki besteht aus einem Schreibpfad und einem Lesepfad, die im einfachen Betrieb als ein einziger Prozess laufen, im großen Betrieb als eigene Komponenten skalieren. Eingehende Logzeilen werden zu Streams gruppiert, wobei ein Stream eine feste Kombination aus Labels ist, und innerhalb eines Streams zu komprimierten Chunks zusammengefasst. Der Index enthält nur die Zuordnung von Label-Kombination zu Chunk, nicht den Inhalt selbst, das ist der entscheidende Unterschied zu Volltext-Systemen. Chunks und Index landen in einem Object Storage, sodass Loki selbst weitgehend zustandslos bleibt und sich leicht ersetzen lässt. Eine Abfrage wählt zuerst über Labels die passenden Streams aus und filtert oder parst danach erst den Text, weshalb die Wahl der Labels über Geschwindigkeit oder Zähigkeit deiner Abfragen entscheidet.

Loki per Helm im Cluster installieren

Für die meisten Cluster reicht der monolithische Modus von Loki: eine Instanz übernimmt Schreiben, Lesen und Komprimieren zusammen. Erst wenn dein Log-Volumen deutlich wächst, lohnt sich der Wechsel in den Modus mit getrennten Komponenten, die du unabhängig skalierst. Ich starte bei neuen Clustern immer im monolithischen Modus und wechsle erst, wenn ich es an den Ressourcenkurven wirklich sehe.

Die Installation läuft wie bei den meisten Charts über das offizielle Helm-Repository von Grafana:

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm upgrade --install loki grafana/loki -n logging --create-namespace -f loki-values.yaml

In der loki-values.yaml legst du fest, wohin Loki seine Chunks schreibt und wie lange sie bleiben sollen. Auf meinen Hetzner-Clustern nutze ich dafür ein S3-kompatibles Object Storage, denselben Ansatz, den ich auch für Backups einsetze:

loki:
  auth_enabled: false
  commonConfig:
    replication_factor: 1
  storage:
    type: s3
    bucketNames:
      chunks: loki-chunks
    s3:
      endpoint: https://fsn1.your-objectstorage.com
      region: fsn1
      s3ForcePathStyle: true
  limits_config:
    retention_period: 720h
singleBinary:
  replicas: 1
  persistence:
    size: 20Gi

storage.type und der s3-Block sagen Loki, wohin die Chunks wandern, replication_factor: 1 passt für einen Single-Binary-Aufbau ohne mehrere Replikas. Der limits_config-Block legt fest, wie lange Logs vorgehalten werden, dazu weiter unten mehr. Nach dem Rollout zeigt kubectl get pods -n logging dir den laufenden Pod. Wie du danach Zustand und Logs von Loki selbst im Blick behältst, steht in kubectl Befehle: die wichtigsten im Alltag.

Alloy statt Promtail: Logs einsammeln

Loki speichert nur, was bei ihm ankommt, das Einsammeln der Logs übernimmt ein eigener Agent auf jeder Node. Über lange Zeit war das Promtail, gebaut speziell für Loki. Promtail wird nicht mehr weiterentwickelt, sein Nachfolger heißt Alloy und deckt neben Logs auch Metriken und Traces mit derselben Konfigurationssprache ab. Wer neu mit dem Loki-Stack startet, setzt direkt auf Alloy, ein Wechsel von einem bestehenden Promtail-Aufbau lohnt sich spätestens dann, wenn du ohnehin an der Log-Pipeline arbeitest.

Alloy läuft wie Promtail als DaemonSet, also mit genau einem Pod je Node, der die Container-Logs dieser Node ausliest und mit Kubernetes-Labels anreichert. Wie ein DaemonSet grundsätzlich funktioniert und wann du eines brauchst, steht in Kubernetes DaemonSet erklärt. Die Konfiguration beschreibt Alloy nicht in YAML, sondern in einer eigenen, deklarativen Sprache aus benannten Komponenten, die sich gegenseitig als Ziele weiterreichen:

discovery.kubernetes "pods" {
  role = "pod"
}

loki.source.kubernetes "pods" {
  targets    = discovery.kubernetes.pods.targets
  forward_to = [loki.write.production.receiver]
}

loki.write "production" {
  endpoint {
    url = "http://loki-gateway.logging.svc/loki/api/v1/push"
  }
}

Die discovery.kubernetes-Komponente findet alle Pods im Cluster über die Kubernetes-API, loki.source.kubernetes liest deren Container-Logs und reicht sie an loki.write weiter, das sie an den Push-Endpunkt von Loki schickt. Jede Komponente reicht ihre Ausgabe an die nächste weiter, ähnlich wie eine Pipe in der Shell, nur als dauerhaft laufender Graph statt als einmaliger Befehl.

Ein Punkt, den du beim DaemonSet mitdenken musst: discovery.kubernetes findet alle Pods im ganzen Cluster, nicht nur die auf der eigenen Node. Ohne Einschränkung sammelt also jede Alloy-Instanz sämtliche Logs ein, und du legst sie so oft in Loki ab, wie du Nodes hast. Dagegen hilft ein discovery.relabel-Schritt zwischen Discovery und Log-Quelle, der die gefundenen Ziele auf den eigenen Node-Namen einkürzt:

discovery.relabel "eigene_node" {
  targets = discovery.kubernetes.pods.targets

  rule {
    source_labels = ["__meta_kubernetes_pod_node_name"]
    regex         = sys.env("NODE_NAME")
    action        = "keep"
  }
}

loki.source.kubernetes "pods" {
  targets    = discovery.relabel.eigene_node.output
  forward_to = [loki.write.production.receiver]
}

Die Discovery liefert zu jedem Ziel das Meta-Label __meta_kubernetes_pod_node_name, und die keep-Regel behält nur die Ziele, deren Node-Name zum eigenen passt. Den eigenen Node-Namen bekommt der Pod über die Downward API in die Umgebungsvariable NODE_NAME, im DaemonSet also über einen env-Eintrag mit fieldRef auf spec.nodeName. In der Alloy-Konfiguration liest sys.env diesen Wert aus. Danach zeigt loki.source.kubernetes nicht mehr direkt auf die Discovery, sondern auf die gefilterte Ausgabe. Die verfügbaren Meta-Labels und die Syntax der Komponenten stehen in der Alloy-Dokumentation zu discovery.kubernetes.

LogQL: Abfragen, die du täglich brauchst

LogQL beginnt immer mit der Auswahl eines Streams über Labels in geschweiften Klammern, danach folgen optionale Filter und Parser. Drei Abfragen decken einen großen Teil des Alltags ab:

# Alle Fehler in einem Namespace der letzten Stunde
{namespace="checkout"} |= "error"

# Antwortzeiten über 500ms aus strukturierten JSON-Logs herausziehen
{app="checkout-api"} | json | duration > 500ms

# Fehlerrate pro Minute als Zahl statt Rohtext
sum(rate({namespace="checkout"} |= "error" [1m]))

Die erste Abfrage zeigt, wie stark LogQL an Grep erinnert: Labels wählen den Stream, |= "error" filtert danach den Text. Die zweite Abfrage parst jede Zeile als JSON und filtert auf ein Feld daraus, das setzt voraus, dass deine Anwendung strukturiert loggt. Die dritte Abfrage verwandelt Logzeilen in eine Zeitreihe, genau wie bei einer Metrik, und lässt sich direkt als Grafana-Panel oder Alarm nutzen. Wer das Label-Prinzip von Prometheus schon kennt, findet sich in LogQL fast sofort zurecht.

Retention und Object-Storage-Backend

Logs wachsen schneller als fast jede andere Datenmenge in einem Cluster, deshalb entscheidet die Retention direkt über deine Kosten. Loki löscht abgelaufene Chunks über eine eigene Komponente, den Compactor, der regelmäßig durch den Object Storage läuft und alles entfernt, was älter ist als die konfigurierte Aufbewahrungszeit:

loki:
  limits_config:
    retention_period: 720h
  compactor:
    retention_enabled: true
    delete_request_store: s3
    working_directory: /loki/compactor

retention_period legt fest, wie lange ein Chunk aufbewahrt wird, retention_enabled schaltet das Löschen im Compactor überhaupt erst frei. Ohne aktivierten Compactor sammelst du Chunks unbegrenzt an, dein Object Storage wächst dann unbemerkt und unbegrenzt weiter. Ich staffle Retention gern nach Umgebung: Entwicklungs- und Testcluster brauchen deutlich kürzere Aufbewahrungszeiten als der Produktionscluster, in dem ich im Zweifel auch Wochen zurückschauen möchte.

Labels: die häufigste Fehlerquelle

Der größte Fehler bei Loki ist fast immer derselbe: zu viele oder zu variable Labels. Jede einzigartige Kombination aus Labels erzeugt einen eigenen Stream, und jeder Stream kostet Index-Einträge. Steckst du eine Request-ID, eine Nutzer-ID oder einen Zeitstempel in ein Label statt in den Log-Text, explodiert die Zahl der Streams, der Index wird riesig, und genau die Abfragen, die eigentlich schnell sein sollten, werden quälend langsam.

Die Regel dahinter ist einfach: Labels beschreiben, woher eine Logzeile kommt, wie Namespace, Anwendung, Pod oder Node, nicht was in ihr steht. Alles, was sich innerhalb eines Pods laufend ändert, gehört in den Log-Text und wird bei der Abfrage per json oder logfmt geparst, nicht als eigenes Label geführt. Wer diese Trennung von Anfang an einhält, hat auch bei Monaten an Logs noch flotte Abfragen.

Häufige Fragen

Loki oder Elasticsearch für Kubernetes Logging?

Loki passt gut, wenn deine Abfragen fast immer mit Labels wie Namespace, Anwendung oder Pod beginnen und du danach im Text filterst, dazu ist der Betrieb schlanker und günstiger. Brauchst du dagegen freie Volltextsuche über beliebige Felder ohne festes Label-Schema, etwa quer über alle Anwendungen, ist Elasticsearch die passendere Wahl.

Promtail oder Alloy: was soll ich einsetzen?

Für einen neuen Aufbau würde ich direkt zu Alloy greifen, es ist der aktive Nachfolger und deckt neben Logs auch Metriken und Traces mit derselben Sprache ab. Läuft bei dir bereits Promtail stabil, musst du nicht sofort wechseln, solltest den Wechsel aber einplanen, sobald du an der Log-Pipeline ohnehin etwas änderst.

Wie lange sollte ich Kubernetes-Logs speichern?

Das hängt von deiner Umgebung und deinen Compliance-Vorgaben ab, eine allgemeingültige Zahl gibt es nicht. Ich fahre kürzere Aufbewahrungszeiten in Entwicklungs- und Testclustern und deutlich längere in der Produktion, gesteuert über retention_period und einen aktivierten Compactor.

Warum sind meine Loki-Abfragen langsam?

In fast allen Fällen liegt es an zu vielen oder zu variablen Labels, die die Zahl der Streams und damit den Index unnötig aufblähen. Prüfe zuerst, ob Request-IDs, Nutzer-IDs oder Zeitstempel versehentlich als Label statt im Log-Text landen, das ist die häufigste Ursache für zähe Abfragen.

Wie du weitermachst

Wenn du Logging und Monitoring zusammendenkst, lohnt sich der Blick auf Kubernetes Monitoring mit Prometheus, denn beide Stacks teilen sich in der Praxis oft dieselben Labels und dieselbe Grafana-Instanz. Für den Alltag mit kubectl rund um Loki, Alloy und die eigentlichen Anwendungen hilft dir kubectl Befehle: die wichtigsten im Alltag, und wenn dir noch nicht klar ist, wie ein DaemonSet wie Alloy überhaupt auf jede Node kommt, steht das in Kubernetes DaemonSet erklärt.

Mein Vorschlag für den Einstieg: Installiere Loki im monolithischen Modus in einem Testnamespace, rolle Alloy als Sammler aus und stelle in Grafana deine erste Abfrage aus einem einzigen Namespace zusammen, bevor du dich an komplexere LogQL-Ausdrücke wagst.

Mein Kubernetes-Praxisbuch bei Rheinwerk widmet Kapitel 8 dem Produktivbetrieb, mit einem eigenen Abschnitt zu Monitoring. Logging selbst behandle ich dort nicht eigenständig, weil es technisch eng mit Monitoring zusammenhängt und deshalb hier als eigener Beitrag mehr Raum bekommt. Alle Informationen zum Buch findest du auf meiner Kubernetes-Seite. Die Details zur Loki-Architektur stehen in der offiziellen Loki-Dokumentation, einen Überblick über Logging-Konzepte in Kubernetes selbst gibt die Kubernetes-Dokumentation zur Logging-Architektur.

Kevin Welter

Kevin Welter

Entwickler, IT-Architekt, Fachbuchautor (Kubernetes, Cloud-Infrastrukturen) und Speaker. Betreibt sein Business mit einer KI-Belegschaft aus acht KI-Mitarbeitern und zeigt Selbstständigen in seiner Community, wie sie ihren ersten KI-Mitarbeiter einstellen.

Mehr über KI-Mitarbeiter

Kubernetes von den Grundlagen bis zum produktionsreifen Cluster

Zum Buch