24.08.2022
Logs aus dem gesamten Cluster sammeln
Kubernetes Logging mit Promtail, Loki und Grafana
Das Lesen von Protokollen aus mehreren Kubernetes-Pods mit kubectl kann schnell umständlich werden. Was wäre, wenn es eine Möglichkeit gäbe, Protokolle aus dem gesamten Cluster an einem einzigen Ort zu sammeln und sie einfach zu filtern, abzufragen und zu analysieren? Hier kommen Promtail, Loki und Grafana ins Spiel.
Table of contents
Einführung (Was ist das, warum brauchen wir es)
Standardmäßig halten Logs in Kubernetes nur während der Lebensdauer eines Pods. Um Logs länger als die Lebensdauer eines einzelnen Pods aufzubewahren, verwenden wir Log-Aggregation. Das bedeutet, dass wir Logs aus verschiedenen Quellen an einem einzigen Ort speichern, um sie auch nach einem Fehler leicht analysieren zu können. Während der ELK-Stack (kurz für Elasticsearch, Logstash, Kibana) eine beliebte Lösung für die Log-Aggregation ist, haben wir uns für etwas leichtgewichtigeres entschieden: Loki.
Entwickelt von Grafana Labs, ist "Loki ein horizontal skalierbares, hochverfügbares, mandantenfähiges Log-Aggregationssystem, das von Prometheus inspiriert ist". Loki ermöglicht eine einfache Sammlung von Logs aus verschiedenen Quellen mit unterschiedlichen Formaten, skalierbare Persistenz über Objektspeicher und einige weitere coole Funktionen, die wir später im Detail erklären werden. Werfen wir jetzt einen Blick auf das von uns erstellte Setup.
Deck
Wenn du nur einen schnellen Blick darauf werfen möchtest, kannst du Deck verwenden, um diesen Stack mit einem Befehl auf deinem Computer einzurichten. Nach der Installation von Deck kannst du Folgendes ausführen:
$ deck get https://raw.githubusercontent.com/Getdeck/wharf/main/loki/deck.yaml
Folge den Anweisungen, die nach Abschluss des Installationsprozesses angezeigt werden, um sich bei Grafana anzumelden und mit der Erkundung zu beginnen.
Setup
In diesem Artikel konzentrieren wir uns auf die Helm-Installation. Grafana Labs bietet eine Reihe von anderen Installationsmethoden an.
Im Helm-Chart-Repository von Grafana findest du 5 Charts, die mit Loki zusammenhängen. Loki-canary ermöglicht dir die Installation von Canary-Builds von Loki in deinem Cluster. Loki-distributed installiert die relevanten Komponenten als Microservices und bietet dir die üblichen Vorteile von Microservices wie Skalierbarkeit, Ausfallsicherheit usw., während du sie unabhängig voneinander konfigurieren kannst. Loki-simple-scalable ist ähnlich, jedoch sind einige der Komponenten immer aktiviert, was einige der Konfigurationsmöglichkeiten einschränkt. Das Chart mit dem Namen Loki wird einen einzelnen StatefulSet in deinem Cluster bereitstellen, der alles enthält, was du zum Ausführen von Loki benötigst. Das letzte in der Gruppe ist loki-stack, das zusätzlich zum Loki-Chart dasselbe StatefulSet bereitstellt, auch Promtail, Grafana und einige andere. Für unseren Anwendungsfall haben wir uns für das Loki-Chart entschieden. Neben Loki selbst werden in unserem Cluster auch Promtail und Grafana ausgeführt. Im folgenden Abschnitt zeigen wir dir, wie du diesen Log-Aggregations-Stack in deinem Cluster installieren kannst!
Voraussetzungen
Um mitzumachen, benötigst du einen Kubernetes-Cluster, auf den du über kubectl zugreifen kannst, und Helm muss auf deinem Computer eingerichtet sein.
Zunächst müssen wir das Chart-Repository von Grafana zu unserer lokalen Helm-Installation hinzufügen und die neuesten Charts abrufen, wie folgt:
$ helm repo add grafana https://grafana.github.io/helm-charts
$ helm repo update
Sobald das erledigt ist, können wir mit dem eigentlichen Installationsprozess beginnen.
Loki Installation
Lass uns damit beginnen, Loki in unserem Cluster zum Laufen zu bringen. Um deine Installation zu konfigurieren, wirf einen Blick auf die Werte, die das Loki-Chart über den Befehl 'helm show values' akzeptiert, und speichere diese in einer Datei.
$ helm show values grafana/loki > loki-values.yaml
Wir werden die Einstellungen nicht im Detail besprechen, da die meisten Werte auf ihren Standardwerten belassen werden können. Du solltest jedoch einen Blick auf den persistence-Schlüssel werfen, um Loki so zu konfigurieren, dass deine Protokolle tatsächlich in einem PersistentVolume gespeichert werden.
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 10Gi
annotations: {}
Sobald du die Werte an deine Vorlieben angepasst hast, installiere Loki in deinem Cluster mit dem folgenden Befehl:
$ helm upgrade --install loki grafana/loki -n loki -f loki-values.yaml
Nachdem das erledigt ist, kannst du überprüfen, ob alles funktioniert hat, indem du kubectl verwendest:
$ kubectl get pods -n loki
NAME READY STATUS RESTARTS AGE
loki-0 1/1 Running 0 1h
Wenn die Ausgabe ähnlich aussieht, herzlichen Glückwunsch! Das ist einer von drei Komponenten, die erfolgreich installiert wurden.
Promtail Installation
Als nächstes schauen wir uns Promtail an. Promtail hat 3 Hauptfunktionen, die für unsere Einrichtung wichtig sind:
- Es erkennt Ziele (Pods, die in unserem Cluster ausgeführt werden)
- Es beschriftet Logstreams (hängt Metadaten wie Pod/Dateinamen usw. an, um sie später einfacher identifizieren zu können)
- Es versendet sie an unsere Loki-Instanz
Um es zu installieren, benötigen wir zuerst eine Werte-Datei, genau wie wir es für Loki getan haben:
$ helm show values grafana/promtail > promtail-values.yaml
Wie bei Loki können die meisten Werte auf ihren Standardwerten belassen werden, um Promtail zum Laufen zu bringen. Wir müssen jedoch Promtail mitteilen, wohin es die gesammelten Protokolle senden soll, indem wir Folgendes tun:
$ kubectl get svc -n loki
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loki ClusterIP 10.101.163.181 <none> 3100/TCP 1h
Wir fragen kubectl nach den Diensten im Loki-Namespace und es wird uns mitgeteilt, dass es einen Dienst namens Loki gibt, der den Port 3100 freigibt. Um Promtail dazu zu bringen, unsere Protokolle an das richtige Ziel zu senden, zeigen wir es über den 'config'-Schlüssel in unserer Werte-Datei auf den Loki-Dienst.
config:
logLevel: info
serverPort: 3101
lokiAddress: http://loki:3100/loki/api/v1/push
Unter 'lokiAddress' geben wir an, dass Promtail Protokolle an 'http://loki:3100/loki/api/v1/push' senden soll. Beachtem dass du, wenn Loki nicht im selben Namespace wie Promtail läuft, die vollständige Service-Adressnotation verwenden musst, z. B. '
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
Wenn du nicht möchtest, dass Promtail auf deinen Master-/Control-Plane-Knoten ausgeführt wird, kannst du dies hier ändern.
Jetzt, da wir die wichtigsten Werte festgelegt haben, lass uns das installieren!
$ helm upgrade --install promtail grafana/promtail --namespace=loki -f promtail-values.yaml
Überprüfe, ob alles wie erwartet funktioniert:
$ kubectl get ds -n loki
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
promtail 8 8 8 8 8 <none> 1h
Du kannst auch mit dem Flag '-o wide' einen Blick auf die Pods werfen, um zu sehen, auf welchem Knoten sie ausgeführt werden:
$ kubectl get pods -n loki -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
promtail-2j9dj 1/1 Running 0 1h 1.1.1.1 control-plane-3 <none> <none>
promtail-5wjxl 1/1 Running 0 1h 1.1.1.1 control-plane-1 <none> <none>
promtail-9nvps 1/1 Running 0 1h 1.1.1.1 worker-1 <none> <none>
promtail-brgj2 1/1 Running 0 1h 1.1.1.1 worker-2 <none> <none>
promtail-cfnff 1/1 Running 0 1h 1.1.1.1 control-plane-2 <none> <none>
promtail-gtt6m 1/1 Running 0 1h 1.1.1.1 worker-3 <none> <none>
promtail-hnh4z 1/1 Running 0 1h 1.1.1.1 worker-4 <none> <none>
promtail-r4xsz 1/1 Running 0 1h 1.1.1.1 worker-5 <none> <none>
Grafana Installation
Zu guter Letzt, lass uns eine Instanz von Grafana in unserem Cluster starten.
Die folgenden Werte ermöglichen die Persistenz. Wenn du möchtest, dass deine Grafana-Instanz E-Mails senden kann, kannst du SMTP wie unten gezeigt konfigurieren. Füge einfach deinen SMTP-Host und 'from_address' hinzu, um ein Secret mit deinen Anmeldeinformationen zu erstellen.
persistence:
type: pvc
enabled: true
# storageClassName: default
accessModes:
- ReadWriteOnce
size: 10Gi
grafana.ini:
smtp:
enabled: true
host: smtp.smtpserver.io:465
from_address: grafana@collectallthelogs.io
skip_verify: true
smtp:
# `existingSecret` is a reference to an existing secret containing the smtp configuration
# for Grafana.
existingSecret: "grafana-smtp"
userKey: "user"
passwordKey: "password"
Sobald du deine Werte konfiguriert hast, kannst du Grafana wie folgt in deinem Cluster installieren:
helm upgrade --install loki-grafana grafana/grafana --namespace=loki -f grafana-values.yaml
Überprüfe, ob alles reibungslos verlaufen ist:
$ kubectl get pods -n loki
NAME READY STATUS RESTARTS AGE
loki-grafana-64b4b79494-8bt7c 1/1 Running 0 1h
Alle drei Komponenten sind einsatzbereit, super! Jetzt, da alles eingerichtet ist, schauen wir uns an, wie wir dies tatsächlich nutzen können.
UNSER KUBERNETES-PODCAST
Werkzeuge für das Handwerk: Die Navigation im Kubernetes-Ökosystem
Michael und Robert sprechen ausführlich über die Feinheiten der lokalen Kubernetes-Entwicklung und geben auch einige echte Codierungsbeispiele.
Weitere Ausgaben unseres Podcasts findest du hier:
Verwendung
Verbinde deine neu erstellte Loki-Instanz einfach mit Grafana. Alles, was du tun musst, ist eine Datenquelle in Grafana zu erstellen. Unter Konfiguration → Datenquellen klicke auf 'Datenquelle hinzufügen' und wähle Loki aus der Liste aus. Dir wird dieses Einstellungsfenster angezeigt, in dem du nur die URL deiner Loki-Instanz konfigurieren musst, um deine Protokolle mit Grafana zu analysieren. Da Grafana im selben Namespace wie Loki läuft, reicht es aus, 'http://loki:3001' anzugeben.
Wenn du fertig bist, klicke auf 'Speichern & Testen' und voilà, du bist bereit, Abfragen gegen Loki auszuführen.
LogQL
‘LogQL ist die von Grafana Loki inspirierte Abfragesprache, ähnlich wie PromQL. Abfragen fungieren wie ein verteilter grep, um Log-Quellen zu aggregieren. LogQL verwendet Labels und Operatoren zur Filterung.’
Mit LogQL kannst du einfach Abfragen gegen deine Protokolle ausführen. Du kannst entweder Protokollabfragen ausführen, um den Inhalt tatsächlicher Protokollzeilen zu erhalten, oder Metrikabfragen verwenden, um Werte basierend auf den Ergebnissen zu berechnen.
LogQL ist gut dokumentiert, daher gehen wir nicht auf jedes Feature im Detail ein, sondern geben dir stattdessen einige Abfragen, die du sofort gegen deine Protokolle ausführen kannst, um loszulegen. Gehe zum Explore-Panel in Grafana (${grafanaUrl}/explore), wähle deine Loki-Datenquelle im Dropdown-Menü aus und schau dir an, was Loki bisher für dich gesammelt hat.
Simple Log Query
Wenn du nur die Protokolle eines einzelnen Pods haben möchtest, ist es so einfach, eine Abfrage wie diese auszuführen:
{pod="loki-0"}
Grafana wählt automatisch das richtige Panel für dich aus und zeigt an, was dein Loki Pod protokolliert.
Fehler in einem Namespace
Diese Abfrage filtert Protokolle aus einem bestimmten Namespace, die das Wort "Fehler" enthalten. Sie zählt sie über den im Dashboard ausgewählten Bereich und gibt die Summe zurück, um dir einen einfachen Überblick darüber zu geben, was in deinem Cluster passiert.
sum(count_over_time({namespace="loki"} |= "error" [$__range]))
Durchschnittliche Antwortzeit in einem Namespace, nach Pfad und Anwendung
Diese Abfrage ist so komplex wie es in diesem Artikel wird. Sie sammelt Protokolle aus einem Namespace und wendet dann mehrere nützliche Funktionen von LogQL an, wie zum Beispiel Musterabgleich, reguläre Ausdrücke, Zeilenformatierung und Filterung. Am Ende erhältst du die durchschnittliche Antwortzeit von Anwendungen, die im angegebenen Namespace innerhalb des ausgewählten Intervalls ausgeführt werden. Sie filtern effektiv die Protokollzeilen heraus, die von Kubernetes Liveness- und Readiness-Probes generiert werden, gruppiert nach App-Label und Pfad. Hinweis: Diese genaue Abfrage funktioniert für das Protokollformat von Django Hurricane, aber du kannst sie anpassen, indem du das Muster an dein Protokollformat anpasst.
avg_over_time({namespace="application"} | pattern "<date> <time> <access> <level> <code> <method> <path> <ip> <latency>" | regexp "(?P<latencyDecimal>[0-9]+\\.[0-9]+ms)" | line_format "{{.latencyDecimal}}" | regexp "(?P<latencyClean>[0-9]+\\.[0-9])" | unwrap latencyClean | __error__="" | path!="/alive" | path!="/ready" [$__interval]) by (path, app)
Sonstige Merkmale/Weitere Lektüre/Heiligtümer
Wenn du deine Logs nicht in deinem Cluster speichern möchtest, kannst du die gesammelten Daten an S3-kompatible Speicherlösungen wie Amazon S3 oder MinIO senden. Der Prozess der Log-Analyse/-Ansicht bleibt derselbe.
Die Dateispeicherung funktioniert nicht, wenn du das verteilte Chart verwendest, da mehrere Pods Lese-/Schreibvorgänge auf demselben PV durchführen müssten. Dies ist im Chart-Repository dokumentiert, wird jedoch leider nicht in der offiziellen Dokumentation von Loki erwähnt.
LogCLI ist das CLI-Tool von Loki, mit dem du deine Protokolle bequem von der Kommandozeile aus durchsuchen kannst. Hierfür musst du deine Loki-Instanz über HTTP freigeben oder Port-Forwarding von deinem Cluster zu deinem Computer verwenden.
Hier sind ein paar Artikel, die du auch interessant finden könntest:
- Grundlagen der API-Strategie: Wie du die richtige Technologie für deine Anwendung auswählst
- Untersuchung der Vor- und Nachteile: Function-as-a-Service (FaaS) vs. Container-Orchestrierung mit Kubernetes
- Die Evolution der Applikationsentwicklung zu einem cloud-native Ansatz
- Minikube vs. k3d vs. kind vs. Getdeck
- Wie geht Kubernetes Development?