Zentrales Logging wird unverzichtbar, sobald Sie mehr als eine Handvoll Server, Container oder Microservices verwalten. Ohne es bedeutet das Debuggen eines Produktionsvorfalls, sich per SSH in einzelne Maschinen einzuloggen und in verstreuten Log-Dateien zu suchen. Log-Aggregation mit Loki, Promtail und Grafana — der PLG-Stack — löst dieses Problem, indem alle Logs in einen einzigen abfragbaren Speicher übertragen werden und die Ressourcenkosten dabei deutlich niedriger bleiben als bei traditionellen Lösungen wie Elasticsearch.

Voraussetzungen

  • Ein Linux-Server (Ubuntu 22.04 oder Debian 12 empfohlen) mit mindestens 2 GB RAM
  • Docker 24+ und Docker Compose v2 installiert
  • Grundlegende Kenntnisse der Grafana-Dashboards (siehe Grafana Dashboards für Infrastruktur-Monitoring)
  • Ports 3000 (Grafana), 3100 (Loki) und 9080 (Promtail) verfügbar
  • Sudo-Zugriff auf dem Host-System

Den PLG-Stack verstehen

Der PLG-Stack besteht aus drei Komponenten, die zusammen als leichte Observability-Pipeline arbeiten:

Promtail ist der Log-Sammel-Agent. Er läuft neben Ihren Anwendungen, liest Log-Dateien oder das systemd-Journal, hängt Labels (Schlüssel-Wert-Metadaten) an und überträgt Log-Streams per HTTP an Loki.

Loki ist das Log-Aggregations-Backend. Anders als Elasticsearch indiziert Loki den Log-Inhalt nicht — es indiziert nur die von Promtail angehängten Labels. Die rohen Log-Zeilen werden komprimiert und als Chunks gespeichert. Diese Architektur macht Loki deutlich günstiger im Betrieb: Ein Cluster, der täglich Gigabytes an Logs verarbeitet, kann mit einigen hundert Megabytes RAM auskommen.

Grafana bietet die Abfrage- und Visualisierungsschicht. Es verbindet sich mit Loki als Datenquelle und ermöglicht LogQL-Abfragen, Dashboard-Erstellung und Alert-Konfiguration — alles in derselben Oberfläche wie für Prometheus-Metriken (siehe Prometheus und Grafana für Server-Monitoring einrichten).

Der Datenfluss ist: Anwendung → Log-Datei/Journal → Promtail → Loki → Grafana.

Loki mit Docker Compose installieren

Erstellen Sie ein Arbeitsverzeichnis und die folgende docker-compose.yml:

version: "3.8"

networks:
  logging:
    driver: bridge

volumes:
  loki_data:
  grafana_data:

services:
  loki:
    image: grafana/loki:3.0.0
    container_name: loki
    ports:
      - "3100:3100"
    volumes:
      - ./loki-config.yaml:/etc/loki/loki-config.yaml
      - loki_data:/loki
    command: -config.file=/etc/loki/loki-config.yaml
    networks:
      - logging

  promtail:
    image: grafana/promtail:3.0.0
    container_name: promtail
    volumes:
      - ./promtail-config.yaml:/etc/promtail/promtail-config.yaml
      - /var/log:/var/log:ro
      - /run/log/journal:/run/log/journal:ro
      - /etc/machine-id:/etc/machine-id:ro
    command: -config.file=/etc/promtail/promtail-config.yaml
    networks:
      - logging
    depends_on:
      - loki

  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=changeme
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - logging
    depends_on:
      - loki

Erstellen Sie loki-config.yaml im selben Verzeichnis:

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: inmemory

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

limits_config:
  retention_period: 30d

compactor:
  working_directory: /loki/compactor
  retention_enabled: true
  delete_request_store: filesystem

Stack starten:

docker compose up -d
docker compose ps

Alle drei Dienste sollten innerhalb von 30 Sekunden den Status healthy oder running anzeigen.

Promtail konfigurieren

Erstellen Sie promtail-config.yaml:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: systemd-journal
        host: ${HOSTNAME}
    relabel_configs:
      - source_labels: [__journal__systemd_unit]
        target_label: unit

  - job_name: varlogs
    static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          host: ${HOSTNAME}
          __path__: /var/log/*.log

  - job_name: docker
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: [__meta_docker_container_name]
        regex: "/(.*)"
        target_label: container
      - source_labels: [__meta_docker_container_label_com_docker_compose_service]
        target_label: service

Die positions-Datei verfolgt, wie weit Promtail in jeder Log-Datei gelesen hat, und verhindert nach Neustarts doppelte Ingestion.

Promtail neu starten, um die Konfiguration anzuwenden:

docker compose restart promtail
docker compose logs promtail --tail=20

Logs mit LogQL abfragen

LogQL ist Lokis Abfragesprache, inspiriert von PromQL. Abfragen haben zwei Teile: einen Stream-Selektor in geschweiften Klammern und optionale Pipeline-Stufen.

Einfacher Stream-Selektor — alle Logs des varlogs-Jobs abrufen:

{job="varlogs"}

Zeilenfilter — Zeilen mit “error” finden:

{job="varlogs"} |= "error"

Regex-Filter — Zeilen nach einem Muster filtern:

{job="systemd-journal"} |~ "fail(ed)?"

Label-Filter nach Parsing — JSON-Logs parsen und nach Level filtern:

{job="varlogs"} | json | level="error"

Metrik-Abfrage — Fehlerrate über Zeit:

rate({job="varlogs"} |= "error" [5m])

Fehler nach Host zählen:

sum by (host) (count_over_time({job="varlogs"} |= "error" [1h]))

Für komplexere Log-Parsing-Muster vergleichen Sie den Ansatz Journalctl: Linux-Systemlogs abfragen und analysieren für rein lokale Szenarien.

Grafana-Dashboards einrichten

Öffnen Sie Grafana unter http://ihr-server:3000 und melden Sie sich mit admin / changeme an.

Loki als Datenquelle hinzufügen:

  1. Gehen Sie zu Verbindungen > Datenquellen > Datenquelle hinzufügen
  2. Wählen Sie Loki
  3. Setzen Sie die URL auf http://loki:3100
  4. Klicken Sie auf Speichern und testen — Sie sollten “Datenquelle verbunden und Labels gefunden” sehen

Log-Explorations-Panel erstellen:

  1. Erstellen Sie ein neues Dashboard und fügen Sie ein Panel hinzu
  2. Wählen Sie Loki als Datenquelle
  3. Wechseln Sie die Visualisierung zu Logs
  4. Geben Sie eine LogQL-Abfrage ein: {job="varlogs"} |= "error"
  5. Aktivieren Sie Deduplizierung und Zeilenumbruch in den Panel-Optionen

Rate-Dashboard aufbauen:

Fügen Sie ein Zeitreihen-Panel mit der Abfrage hinzu:

sum by (host) (rate({job="varlogs"} |= "error" [5m]))

Dies liefert ein Echtzeit-Fehlerrate-Diagramm aufgeteilt nach Server.

Alerts auf Log-Muster einrichten

Loki enthält eine Ruler-Komponente, die LogQL-Metrikabfragen nach einem Zeitplan auswertet und Alerts an Alertmanager sendet.

Ruler-Konfiguration zur loki-config.yaml hinzufügen:

ruler:
  storage:
    type: local
    local:
      directory: /loki/rules
  rule_path: /loki/rules-temp
  alertmanager_url: http://alertmanager:9093
  enable_api: true

Erstellen Sie /loki/rules/fake/rules.yaml:

groups:
  - name: log-alerts
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate({job="varlogs"} |= "error" [5m])) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Hohe Fehlerrate in System-Logs erkannt"
          description: "Die Fehler-Log-Rate hat 0.1 Zeilen/Sek. für 5 Minuten überschritten."

      - alert: SSHAuthFailures
        expr: |
          sum(count_over_time({unit="sshd.service"} |= "Failed password" [10m])) > 10
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Mehrfache SSH-Authentifizierungsfehler"
          description: "Mehr als 10 SSH-Auth-Fehler in 10 Minuten — möglicher Brute-Force-Angriff."

Loki vs. ELK vs. Graylog — Vergleich

MerkmalLokiELK StackGraylog
IndizierungsstrategieNur LabelsVolltext-IndexVolltext-Index
RAM-Nutzung (10 GB/Tag)~512 MB8–16 GB4–8 GB
AbfragespracheLogQLKQL / LuceneGELF / Elasticsearch
Grafana-IntegrationNativPlugin erforderlichPlugin erforderlich
Setup-KomplexitätGeringHochMittel
Horizontale SkalierbarkeitGut (Microservices-Modus)HervorragendGut
Kosten bei SkalierungSehr geringHochMittel
Am besten fürKubernetes-/Container-LogsVolltext-Suche in LogsCompliance, SIEM

Loki gewinnt bei Kosten und Einfachheit, wenn Ihr Hauptbedarf Log-Aggregation und Korrelation mit Metriken ist. Für einen Vergleich mit der Elasticsearch-Einrichtung siehe Elasticsearch für Log-Analyse einrichten.

Praxisbeispiel

Sie verwalten 15 Produktionsserver mit einer Mischung aus Nginx, PostgreSQL und benutzerdefinierten Python-APIs. Vorfälle passieren, aber die Ursachenanalyse dauert Stunden, weil Logs auf 15 Maschinen verteilt sind. So löst PLG dieses Problem:

  1. Stellen Sie Promtail auf jedem Server über ein Konfigurationsverwaltungstool (Ansible/Puppet) bereit und richten Sie alle Instanzen auf einen einzigen Loki-Endpunkt aus.
  2. Fügen Sie Labels host und env hinzu, sodass jeder Log-Stream mit dem Ursprungsserver und der Umgebung (Produktion/Staging) markiert ist.
  3. Erstellen Sie in Grafana ein Dashboard mit einer Variable $host, die an die host-Label-Werte gebunden ist. Jetzt zeigt ein einziges Dashboard Logs aller 15 Server mit einem Dropdown zum Filtern nach Host.
  4. Fügen Sie eine Alert-Regel hinzu, die auslöst, wenn ein Host mehr als 50 Fehlerzeilen pro Minute produziert — Sie erhalten eine Slack-Benachrichtigung, bevor Benutzer das Problem melden.
  5. Verwenden Sie bei Vorfällen die Explore-Ansicht, um Logs und Prometheus-Metriken nebeneinander zu korrelieren: Fehler-Spike in Logs um 14:32 → CPU-Spike auf demselben Host um 14:31.

Dieser Workflow ersetzt eine 45-minütige manuelle SSH-Untersuchung durch einen 3-minütigen Grafana-Drill-Down.

Stolperfallen und Sonderfälle

Label-Kardinalitätsexplosion. Jede eindeutige Label-Kombination erstellt einen separaten Log-Stream. Verwenden Sie niemals hochkardinale Werte (Benutzer-IDs, UUIDs, Anfrage-IDs) als Labels. Halten Sie Labels bei stabilen, wenig variierenden Werten: host, job, env, service.

Aufbewahrungskonfiguration. Der retention_period in limits_config erfordert, dass der Compactor mit retention_enabled: true aktiviert ist. Ohne dies speichert Loki Logs unbegrenzt, bis der Speicher voll ist.

Chunk-Cache und Arbeitsspeicher. Loki speichert unkomprimierte Chunks während der Ingestion im Arbeitsspeicher. Auf Servern mit weniger als 2 GB RAM setzen Sie chunk_target_size: 1048576 und max_chunk_age: 1h, um den Speicherdruck zu begrenzen.

Verlust der Promtail-Positions-Datei. Wenn der Promtail-Container ohne persistentes Volume für /tmp/positions.yaml neu erstellt wird, liest er alle Log-Dateien von Anfang an und ingestiert Duplikate. Binden Sie die Positions-Datei immer auf einem persistenten Volume ein.

Log-Reihenfolge. Loki erfordert, dass Log-Zeilen innerhalb eines einzelnen Streams in Timestamp-Reihenfolge ingestiert werden. Wenn Ihre Anwendung Logs mit ungeordneten Timestamps schreibt, aktivieren Sie unordered_writes: true in der Loki-Ingester-Konfiguration.

Docker-Socket-Zugriff. Die Docker-SD-Konfiguration in Promtail benötigt Zugriff auf den Docker-Socket. Der Promtail-Container muss entweder als root laufen oder der docker-Gruppe hinzugefügt werden.

Zusammenfassung

  • Der PLG-Stack (Promtail + Loki + Grafana) bietet zentrale Log-Aggregation zu einem Bruchteil der ELK-Kosten
  • Loki indiziert nur Labels, nicht den Log-Inhalt — minimaler Speicher- und RAM-Verbrauch
  • LogQL Stream-Selektoren ({job="varlogs"}) plus Pipeline-Stufen (|= "error", | json) ermöglichen leistungsstarke Log-Filterung
  • Promtail scrapt systemd-Journal, Dateien und Docker-Container-Logs mit automatischer Label-Zuordnung
  • Die Loki-Datenquelle in Grafana ermöglicht einheitliche Dashboards mit Logs (Loki) und Metriken (Prometheus)
  • Hochkardinale Labels sind der häufigste Loki-Performance-Fehler — halten Sie Label-Werte stabil und gering
  • Loki-Alert-Regeln verwenden LogQL-Metrikabfragen, die vom Ruler-Komponenten ausgewertet werden

Verwandte Artikel