TL;DR — Kurzzusammenfassung

Grafana Loki für zentralisierte Log-Aggregation mit Promtail einrichten. LogQL, Dashboards, Alerting und Multi-Tenant-Konfiguration für die Produktion erklärt.

Grafana Loki ist ein horizontal skalierbares Log-Aggregationssystem, das auf denselben Prinzipien wie Prometheus aufbaut — es indiziert nur Labels, nicht den vollständigen Log-Text, was es dramatisch günstiger als den ELK-Stack macht. Diese Anleitung behandelt Lokis Architektur, Installation via Docker Compose, Promtail-Konfiguration, die LogQL-Abfragesprache, Dashboard-Erstellung in Grafana, Alerting, Multi-Tenancy und Produktions-Sizing.

Voraussetzungen

  • Docker und Docker Compose (oder ein Kubernetes-Cluster für Helm-basierte Installation).
  • Grafana 10+ (oder Grafana Cloud) zur Visualisierung.
  • Grundkenntnisse in YAML-Konfiguration und Kommandozeilen-Tools.

Loki-Architektur

Loki verteilt seine Arbeit auf vier Hauptkomponenten:

  • Distributor — Empfängt Log-Streams von Promtail/Agenten, validiert Labels und verteilt sie über Consistent Hashing an die Ingester.
  • Ingester — Hält aktuelle Logs im Arbeitsspeicher (konfigurierbare Chunk-Größe), schreibt komprimierte Chunks in den Objektspeicher und pflegt ein WAL für Absturzsicherheit.
  • Querier — Führt LogQL-Abfragen sowohl auf in-memory (aktuellen) als auch auf gespeicherten (historischen) Chunks aus.
  • Compactor — Zusammenführen und Deduplizieren der boltdb-shipper-Indextabellen und Durchsetzen von Aufbewahrungsrichtlinien.

Im monolithischen Modus (Standard für Einzelknoten-Installationen) laufen alle vier Komponenten in einem einzigen Binary. Wenn das Log-Volumen ~50 GB/Tag übersteigt, empfiehlt sich der Wechsel zum Microservices-Modus, in dem jede Komponente unabhängig skaliert.

Das zentrale Design-Konzept: Loki erstellt niemals einen invertierten Index des Log-Inhalts. Eine Abfrage mit |= "OutOfMemoryError" führt ein verteiltes Grep über die Chunks durch, die den ausgewählten Labels entsprechen.


Warum Loki statt ELK?

MerkmalLokiElasticsearch
IndizierungsmodellNur LabelsInvertierter Volltext-Index
Speicherkosten~10x wenigerHoch (Index + Daten)
AbfragespracheLogQL (ähnlich PromQL)Lucene / KQL
Nativ in GrafanaJa — erstklassigVia Plugin
Horizontale SkalierungJa (Label-Sharding)Ja (Shards)
Schema-ÄnderungenNicht erforderlichRe-Indizierung nötig
AlertingLoki Ruler + AlertmanagerElastAlert / SIEM
Kubernetes-nativJa (Helm Chart)Ja (ECK Operator)

Schritt 1: Installation mit Docker Compose

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

version: "3.8"
services:
  loki:
    image: grafana/loki:3.0.0
    ports:
      - "3100:3100"
    volumes:
      - ./loki-config.yaml:/etc/loki/local-config.yaml
      - loki-data:/loki
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:3.0.0
    volumes:
      - ./promtail-config.yaml:/etc/promtail/config.yaml
      - /var/log:/var/log:ro
      - /run/log/journal:/run/log/journal:ro
    command: -config.file=/etc/promtail/config.yaml

  grafana:
    image: grafana/grafana:10.4.0
    ports:
      - "3000:3000"
    environment:
      GF_AUTH_ANONYMOUS_ENABLED: "true"
      GF_AUTH_ANONYMOUS_ORG_ROLE: Admin

volumes:
  loki-data:

Schritt 2: Loki konfigurieren

Erstellen Sie loki-config.yaml:

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

ingester:
  lifecycler:
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
  chunk_idle_period: 5m
  chunk_retain_period: 30s
  wal:
    enabled: true
    dir: /loki/wal

schema_config:
  configs:
    - from: 2024-01-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v12
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /loki/index
    cache_location: /loki/boltdb-cache
    shared_store: filesystem
  filesystem:
    directory: /loki/chunks

compactor:
  working_directory: /loki/compactor
  shared_store: filesystem
  compaction_interval: 10m
  retention_enabled: true
  retention_delete_delay: 2h

limits_config:
  retention_period: 30d
  ingestion_rate_mb: 16
  ingestion_burst_size_mb: 32
  max_query_length: 721h

Schritt 3: 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: nginx
    static_configs:
      - targets: [localhost]
        labels:
          job: nginx
          env: prod
          __path__: /var/log/nginx/access.log

  - job_name: docker
    static_configs:
      - targets: [localhost]
        labels:
          job: docker
          __path__: /var/lib/docker/containers/*/*-json.log
    pipeline_stages:
      - json:
          expressions:
            log: log
            stream: stream
      - output:
          source: log

Starten Sie den Stack:

docker compose up -d
docker compose logs -f loki

Schritt 4: LogQL-Abfragesprache

LogQL hat zwei Formen: Log-Abfragen und Metrik-Abfragen.

Stream-Selektoren (erforderlich, immer zuerst):

{job="nginx"}
{job="nginx", env="prod"}
{job=~"nginx|apache"}

Filterausdrücke (Pipe nach dem Selektor):

{job="nginx"} |= "error"
{job="nginx"} != "health_check"
{job="nginx"} |~ "5[0-9]{2}"

Parser-Ausdrücke — Felder aus strukturierten Logs extrahieren:

{job="app"} | json
{job="app"} | logfmt
{job="app"} | json | level="error"

Metrik-Abfragen — Logs in Zeitreihen umwandeln:

rate({job="nginx"} |= "error" [5m])
count_over_time({job="app"} | json | level="error" [1h])
sum by (status) (rate({job="nginx"} | logfmt | status=~"5.." [5m]))
topk(5, sum by (uri) (rate({job="nginx"}[10m])))

Schritt 5: Grafana-Datenquelle und Dashboards

  1. In Grafana gehen Sie zu Connections → Data sources → Add data source → Loki.
  2. Setzen Sie die URL auf http://loki:3100 (oder Ihre Loki-Adresse).
  3. Klicken Sie auf Save & test — Sie sehen “Data source connected.”

Tipps für das Explore-Panel:

  • Verwenden Sie Live tail für das Echtzeit-Streaming von Logs — ideal zum Debuggen von Deployments.
  • Klicken Sie auf eine Log-Zeile, um den Log-Kontext zu sehen — Zeilen vor und nach dem Treffer.
  • Wechseln Sie zum Metrics-Tab, um rate()-Abfragen als Zeitreihen-Panels zu visualisieren.

Schritt 6: Alerting mit dem Loki Ruler

Fügen Sie einen ruler-Block zur loki-config.yaml hinzu:

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

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

groups:
  - name: app-alerts
    interval: 1m
    rules:
      - alert: HoheFehlerate
        expr: |
          sum(rate({job="app"} | json | level="error" [5m])) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Hohe Fehlerrate in den App-Logs"

Loki vs. Alternativen

ToolSpeichermodellSelf-hostedKostenNativ GrafanaAm besten geeignet für
LokiLabel-Index + komprimierte ChunksJaNiedrigJaTeams mit Grafana/Prometheus
ElasticsearchInvertierter Volltext-IndexJaHochVia PluginVolltextsuche, SIEM
FluentdNur Agent (kein Speicher)JaKostenlosNeinLog-Routing und Transformation
Datadog LogsSaaS, proprietärNeinHochNeinEnterprise, vollständige Observability
CloudWatch LogsSaaS (AWS)NeinMittelVia PluginNative AWS-Workloads

Multi-Tenancy

Aktivieren Sie Multi-Tenancy mit auth_enabled: true in Loki. Jede Anfrage muss X-Scope-OrgID: <tenant-id> enthalten. Konfigurieren Sie Promtail so, dass der Header gesendet wird:

clients:
  - url: http://loki:3100/loki/api/v1/push
    tenant_id: team-backend

Produktions-Sizing-Empfehlungen

Log-VolumenArchitekturSpeicherRAM
< 5 GB/TagMonolithisch, EinzelknotenLokales Filesystem2 GB
5–50 GB/TagMonolithisch + S3/GCSObjektspeicher4–8 GB
50–500 GB/TagMicroservices, 3 IngesterObjekt + TSDB16–32 GB
> 500 GB/TagMicroservices + Thanos RulerObjekt, Multi-AZ64 GB+

Aktivieren Sie immer das WAL (ingester.wal.enabled: true) in der Produktion, um Datenverlust bei Ingester-Neustarts zu verhindern.


Fehlerbehebung

ProblemLösung
connection refused beim SendenPrüfen Sie, ob der Loki-Container läuft und Port 3100 von Promtail erreichbar ist
Query-TimeoutErhöhen Sie querier.query_timeout und teilen Sie Abfragen in kürzere Zeitbereiche auf
Fehlende Docker-LogsPrüfen Sie Promtails positions.yaml für den Container-Log-Pfad
Hoher Ingester-SpeicherReduzieren Sie chunk_idle_period, um Chunks früher in den Speicher zu schreiben
Aufbewahrung funktioniert nichtStellen Sie sicher, dass compactor.retention_enabled: true und limits_config.retention_period gesetzt sind

Zusammenfassung

  • Nur Label-Indizierung macht Loki 10x günstiger als Elasticsearch bei gleichem Volumen.
  • Promtail sendet Logs aus Dateien, systemd-Journal und Docker mit Label-Anreicherung.
  • LogQL unterstützt Stream-Filterung, JSON/logfmt-Parsing, Ratenberechnung und Aggregation.
  • Der Loki Ruler wertet LogQL-Alerts nach einem Zeitplan aus und leitet sie an Alertmanager weiter.
  • Für die Produktion ersetzen Sie den Filesystem-Speicher durch S3/GCS und aktivieren WAL und Chunk-Caching.

Verwandte Artikel