Effizientes Logging mit Grafana Alloy: Die optimale Lösung für Raspberry Pi
Logging mit Grafana Alloy bietet ein ressourcenoptimiertes Überwachungssystem speziell für eine Raspberry Pi Umgebungen.
DarkWolfCave.de
Diese technische Kombination aus Loki als Backend und Alloy als Sammler ermöglicht eine strukturierte Erfassung aller relevanten Systemlogs durch selektive Metadaten-Indizierung anstelle speicherhungriger Volltext-Indexierung.
Das Ergebnis: Eine performante Log-Analyse bei minimalem RAM- und CPU-Verbrauch – entscheidend für ressourcenbeschränkte Systeme. Die vorliegende Anleitung führt dich systematisch durch die komplette Implementierung mittels Docker-Container, von der Grundinstallation über die Konfiguration der Erfassungsquellen bis zum praktischen Dashboard-Setup für das tägliche Monitoring.
Logging mit Grafana Alloy und Loki
Ein zentrales Logging-System ist für jedes Homelab eine kritische Komponente zur Fehlerdiagnose und Systemüberwachung.
In dieser Anleitung zeige ich dir die Implementierung eines ressourceneffizienten Logging-Systems auf Basis von Grafana Loki und dem Alloy Agent für Raspberry Pi. Wie üblich werde ich alles in Docker-Containern bereitstellen.
Technische Komponenten im Überblick:
- Grafana Loki: Ein horizontal skalierbares Log-Aggregationssystem, das Metadaten (Labels) statt Volltextindizes nutzt und dadurch minimale Ressourcen verbraucht
- Grafana Alloy Agent: Der moderne Nachfolger von Promtail, konzipiert für effiziente Log-Sammlung aus diversen Quellen
- Docker & Docker Compose: Für die Containerisierung und vereinfachte Verwaltung der Dienste
- Traefik: Als optionaler Reverse Proxy für die zentrale Zugriffsverwaltung – sehr hilfreich, um sich nicht immer alle Ports für die jeweilige Anwendung merken zu müssen.
Vorteile dieser Logging-Lösung:
- leicht erweiterbar für unter anderem Docker-Container, diverse Anwendungslogs und Netzwerkgeräte
- Optimiert für ressourcenbeschränkte Systeme wie Raspberry Pi
- Erfassung und Zentralisierung aller Systemlogs (systemd, Paketmanager, Anwendungen)
- Leistungsfähige Abfrage- und Filtermöglichkeiten durch Grafana
Systemvoraussetzungen für Logging mit Grafana Alloy
Für die erfolgreiche Implementierung dieses Logging-Systems benötigst du:
Hardware:
- Raspberry Pi 4 mit mindestens 2 GB RAM (4 GB+ empfohlen für umfangreichere Logging-Anforderungen)
- Mindestens 16 GB SD-Karte, besser 32 GB+ für längere Log-Aufbewahrung (am besten eine SSD)
- Stabiles Netzteil mit 5V/3A
Software:
- Raspberry Pi OS 64-Bit (Bullseye oder neuer) oder kompatible Linux-Distribution
- SSH-Zugriff auf den Raspberry Pi
- Internetverbindung für Container-Downloads
Erforderliche Kenntnisse:
- Grundlegende Linux-Befehle und Terminal-Nutzung
- Einfaches Verständnis für Docker-Konzepte
- Grundkenntnisse in Netzwerkkonfiguration
Optionale Komponenten:
- Pi-hole für lokale DNS-Auflösung (Alternative zu Host-Datei-Anpassungen)
- Bestehender Reverse Proxy (falls vorhanden)
Auf dieser Hardware laufen meine Umgebungen
Bei mir gibt es mehrere sogenannte »Umgebungen«, die ich benutze.
Zum einen meine »Live« oder auch »Produktion« Umgebung, auf der alles läuft, was ich in meinem Netzwerk so benötige.
Dann gibt es noch Umgebungen für unterschiedliche Szenarien: ein Labor (LAB), eine Entwickler (DEV) und eine zum finalen Testen (UAT).
Hardwaretechnisch sind aber alle fast gleich ausgestattet, da ich mit diesen Kombinationen bisher nie Probleme hatte.
Lediglich setzt meine neue Live-Umgebung erstmalig auf eine NVMe-SSD.
Werbung
Aktuelle Produktions-Umgebung (live)
Preview | Product | Price | |
---|---|---|---|
|
Raspberry Pi 5 8 GB |
91,88 EUR |
Bei Amazon kaufen |
|
offizieller Raspberry Pi 5 USB-C Netzteil 27W, USB-C… |
18,72 EUR |
Bei Amazon kaufen |
|
GeeekPi Raspberry Pi 5 Aluminiumgehäuse mit Official… |
23,98 EUR |
Bei Amazon kaufen |
|
GeeekPi N04 M.2 M-Key NVMe SSD Shield für Raspberry Pi… |
19,99 EUR
12,95 EUR |
Bei Amazon kaufen |
|
Crucial P3 Plus SSD 1TB M.2 PCIe Gen4 NVMe Interne SSD,… |
74,99 EUR |
Bei Amazon kaufen |
|
SanDisk Extreme 32 GB microSDHC Memory Card + SD… |
14,99 EUR
7,79 EUR |
Bei Amazon kaufen |
|
Transcend 32GB kleiner und kompakter USB-Stick 3.1 Gen… |
16,62 EUR |
Bei Amazon kaufen |
|
UGREEN USB C 312MB/S Kartenleser SD 4.0 Kartenleser USB… |
25,99 EUR
19,94 EUR |
Bei Amazon kaufen |
Letzte Aktualisierung am 24.04.2025 (Preise können abweichen) / Infos zu Affiliate Links / Bilder von der Amazon Product Advertising API
Affiliate – Links
DarkWolfCave.de ist Teilnehmer des Amazon-Partnerprogramm, das zur Bereitstellung eines Mediums für Webseiten konzipiert wurde, mittels dessen durch die Platzierung von Partner-Links zu Amazon.de Entgelte verdient werden können.
Werbung
Test-Umgebungen (UAT/DEV/LAB)
Preview | Product | Price | |
---|---|---|---|
|
Raspberry Pi 5 4GB |
69,69 EUR |
Bei Amazon kaufen |
|
Raspberry Pi 4 Modell B (8 GB) |
86,53 EUR
83,96 EUR |
Bei Amazon kaufen |
|
Raspberry Pi 4 Modell B (4 GB) | 129,00 EUR 72,70 EUR | Bei Amazon kaufen |
|
Raspberry Pi Raspberry Fuente de Alimentación USB-C… |
13,53 EUR |
Bei Amazon kaufen |
|
Miuzei Gehäuse für Raspberry Pi 4 mit Lüfter, 5.1V… |
17,99 EUR |
Bei Amazon kaufen |
|
SD kartenleser 5 in 1 USB 3.0, Aluminiumlegierung mit… | Bei Amazon kaufen | |
|
Samsung MZ-76E1T0B/EU 860 EVO 1 TB SATA 2,5″ Interne… |
135,00 EUR |
Bei Amazon kaufen |
|
UGREEN Festplattengehäuse 2,5 Zoll USB C 3.2 Gen 2 auf… |
19,99 EUR
11,89 EUR |
Bei Amazon kaufen |
|
JSAUX Adapter |
11,99 EUR |
Bei Amazon kaufen |
Letzte Aktualisierung am 25.04.2025 (Preise können abweichen) / Infos zu Affiliate Links / Bilder von der Amazon Product Advertising API
Affiliate – Links
DarkWolfCave.de ist Teilnehmer des Amazon-Partnerprogramm, das zur Bereitstellung eines Mediums für Webseiten konzipiert wurde, mittels dessen durch die Platzierung von Partner-Links zu Amazon.de Entgelte verdient werden können.
Grundinstallation: Docker und Docker Compose
Falls Docker bisher nicht auf deinem Raspberry Pi installiert ist, hier eine grobe Anleitung:
Oder schaue dir den entsprechenden Artikel von mir dazu an.
Docker installieren
# System-Pakete aktualisieren sudo apt update sudo apt upgrade -y # Docker installieren curl -sSL https://get.docker.com | sh # Deinen Benutzer zur Docker-Gruppe hinzufügen sudo usermod -aG docker $USER # Einmal die Gruppenrichtlinien neu starten newgrp docker
Docker Compose installieren
# Die neueste Version von Docker Compose herunterladen sudo apt-get install -y docker-compose-plugin # Überprüfen, ob Docker Compose korrekt installiert wurde docker compose version
Traefik – Was ist ein Reverse Proxy und wofür benötigen wir ihn?
Ein Reverse Proxy ist ein Server, der Anfragen von Clients entgegennimmt und an die entsprechenden Backend-Server weiterleitet.
In meinem Setup verwende ich Traefik als Reverse Proxy aus folgenden Gründen:
- Vereinfachter Zugriff: Du kannst über einen Domainnamen (z.B. loki.local) auf deine Dienste zugreifen, statt über IP-Adressen und Ports.
- Zentrales Routing: Alle deine Dienste können über einen einzigen Einstiegspunkt erreichbar sein.
- Automatische SSL-Verschlüsselung: Traefik kann automatisch Let’s Encrypt-Zertifikate für deine Dienste verwalten. (was aber in einem lokalen Netzwerk eher unnötig und auch nicht ganz so einfach einzurichten ist.)
- Load Balancing: Bei mehreren Instanzen eines Dienstes kann Traefik die Last verteilen. (aber eher bei einem Kubernetes Setup oder Docker Swarm interessant)
Traefik als Reverse Proxy einrichten
Wenn du bereits einen anderen Reverse Proxy (wie Nginx oder HAProxy) verwendest, kannst du diesen Abschnitt überspringen und deine Dienste entsprechend konfigurieren. Ich erkläre dir grob, wie du Traefik als Docker Container einrichten kannst. Weitere Informationen findest du in einem ausführlichen Artikel von mir.
Erstelle ein Verzeichnis für Traefik:
mkdir -p ~/docker/traefik/config cd ~/docker/traefik
Erstelle eine docker-compose.yml
für Traefik:
nano docker-compose.yml
Füge folgenden Inhalt ein:
services: traefik: image: traefik:latest container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true ports: - "80:80" # HTTP - "8080:8080" # Traefik Dashboard volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # Docker-Socket für Container-Erkennung - ./config/traefik.yml:/etc/traefik/traefik.yml:ro # Hauptkonfiguration networks: - traefik_network labels: - "traefik.enable=true" # Dashboard lokal verfügbar machen - "traefik.http.routers.dashboard.rule=Host(`traefik.local`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.entrypoints=web" networks: traefik_network: name: traefik_network
Erstelle die Traefik-Konfigurationsdatei:
cd config nano traefik.yml
Füge folgenden Inhalt ein:
# Globale Konfiguration global: checkNewVersion: true sendAnonymousUsage: false # Log-Konfiguration log: level: INFO # Für detailliertere Logs während der Einrichtung: level: DEBUG # Traefik API und Dashboard aktivieren api: dashboard: true insecure: true # Im lokalen Netzwerk akzeptabel # EntryPoints konfigurieren (Zugangspunkte für Anfragen) entryPoints: web: address: ":80" # Provider konfigurieren providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false # Container müssen explizit per Label aktiviert werden network: traefik_network
Starte Traefik:
cd .. docker compose up -d
DNS-Konfiguration für Traefik und Applikationen
Für den Zugriff auf die Applikationen über Hostnamen statt IP-Adressen stehen unter anderem zwei Methoden zur Verfügung:
Methode 1: Hosts-Datei anpassen
Diese Methode erfordert die Anpassung der Hosts-Datei auf jedem Client-Gerät, von dem aus du auf die Logging-Dienste zugreifen möchtest:
Für Windows:
- Öffne Notepad als Administrator
- Öffne die Datei
C:\Windows\System32\drivers\etc\hosts
- Füge folgende Zeilen hinzu (ersetze
192.168.1.100
durch die IP-Adresse deines Raspberry Pi)
192.168.1.100 traefik.local 192.168.1.100 loki.local 192.168.1.100 alloy.local 192.168.1.100 grafana.local
- Speichere die Datei
Für Linux/macOS:
sudo nano /etc/hosts
Füge die gleichen Einträge wie oben hinzu und speichere die Datei.
Methode 2: Pi-hole für zentrale DNS-Verwaltung (Empfohlen)
Pi-hole bietet eine zentralisierte Möglichkeit, lokale DNS-Einträge für alle Netzwerkgeräte zu verwalten:
- Öffne das Pi-hole Admin-Dashboard (typischerweise
http://pi.hole/admin
) - Navigiere zu „Local DNS“ > „DNS Records“
- Füge folgende Einträge hinzu:
- Domain:
traefik.local
→ IP:<Raspberry Pi IP>
- Domain:
loki.local
→ IP:<Raspberry Pi IP>
- Domain:
alloy.local
→ IP:<Raspberry Pi IP>
- Domain:
grafana.local
→ IP:<Raspberry Pi IP>
- Domain:
Vorteile der Pi-hole-Methode:
- Einmalige zentrale Konfiguration
- Automatische Namensauflösung für alle Netzwerkgeräte
- Kombination mit Werbeblockierung und weiteren DNS-Funktionen
Die Pi-hole-Methode ist besonders für Heimnetzwerke mit mehreren Geräten zu empfehlen, während die Hosts-Datei-Methode für einzelne Testsysteme ausreichend ist.
Installation und Konfiguration von Grafana
Grafana dient als Visualisierungsplattform für unser Logging-System mit Alloy und Loki. Die folgende Anleitung beschreibt die Docker-basierte Installation:
Verzeichnisstruktur anlegen
mkdir -p ~/docker/grafana/data cd ~/docker/grafana
Docker Compose Konfiguration erstellen
nano docker-compose.yml
Füge folgenden Inhalt ein:
services: grafana: image: grafana/grafana:latest container_name: grafana restart: unless-stopped user: "1000" # Anpassen an die UID des eigenen Benutzers, ggf. mit 'id -u' ermitteln environment: - GF_SECURITY_ALLOW_EMBEDDING=true - GF_AUTH_ANONYMOUS_ENABLED=false volumes: - ./data:/var/lib/grafana networks: - traefik_network labels: - "traefik.enable=true" - "traefik.http.routers.grafana.rule=Host(`grafana.local`)" - "traefik.http.routers.grafana.entrypoints=web" - "traefik.http.services.grafana.loadbalancer.server.port=3000" networks: traefik_network: external: true
Grafana starten und verifizieren
docker compose up -d docker logs grafana
Überprüfe die Logs auf Fehlermeldungen. Bei erfolgreicher Installation und den notwendigen Einträgen in Pi-hole oder der Hosts-Datei sollte Grafana unter http://grafana.local erreichbar sein.
Erstanmeldung und Passwort ändern
- Öffne http://grafana.local im Browser
- Melde dich mit den Standard-Zugangsdaten an:
- Benutzername:
admin
- Passwort:
admin
- Benutzername:
- Ändere bei Aufforderung das Standardpasswort in ein sicheres Passwort
- Notiere das neue Passwort an einem sicheren Ort
Du wirst hier einen groben Überblick finden.
Allerdings biete ich dir auch noch etwas mehr Support an:
- Du benötigst persönlichen Support
- Du möchtest von Beginn an Unterstützung bei deinem Projekt
- Du möchtest ein hier vorgestelltes Plugin durch mich installieren und einrichten lassen
- Du würdest gerne ein von mir erstelltes Script etwas mehr an deine Bedürfnisse anpassen
Für diese Punkte und noch einiges mehr habe ich einen limitierten
VIP-Patreon Tarif
eingerichtet. Falls er dir dort zurzeit nicht angeboten wird,
kontaktiere mich bitte über Discord und wir finden eine Lösung!
Installation von Loki und Alloy
Nach der erfolgreichen Einrichtung von Traefik und Grafana folgt nun die Installation der zentralen Logging-Komponenten Loki und Alloy.
Verzeichnisstruktur erstellen
Erstelle ein dediziertes Verzeichnis für das Logging-Setup:
mkdir -p ~/docker/logging/ cd ~/docker/logging
Konfigurationsdateien erstellen
Wir erstellen nun die drei erforderlichen Konfigurationsdateien, und ich erkläre dir ein paar Details dazu.
Docker Compose für Loki und Alloy
Erstelle die Docker Compose-Datei:
nano docker-compose.yml
Mit diesem Inhalt haben wir direkt Loki und Alloy in einer Compose-Datei:
services: loki: image: grafana/loki:latest container_name: loki_traefik restart: unless-stopped volumes: - ./loki-config.yml:/etc/loki/loki-config.yml - loki-data:/loki networks: - traefik_network labels: - "traefik.enable=true" - "traefik.http.routers.loki.rule=Host(`loki.local`)" - "traefik.http.routers.loki.entrypoints=web" - "traefik.http.services.loki.loadbalancer.server.port=3100" alloy: image: grafana/alloy:latest container_name: alloy_traefik restart: unless-stopped environment: - ALLOY_CONFIG=/etc/alloy/config.alloy - HOSTNAME=${HOSTNAME:-raspberrypi} # Verwendet Systemhostnamen oder Fallback volumes: - ./alloy-config.yml:/etc/alloy/config.alloy - /var/log:/var/log:ro - /var/log/journal:/var/log/journal:ro - /var/log/unifi:/var/log/unifi:ro networks: - traefik_network labels: - "traefik.enable=true" - "traefik.http.routers.alloy.rule=Host(`alloy.local`)" - "traefik.http.routers.alloy.entrypoints=web" - "traefik.http.services.alloy.loadbalancer.server.port=12345" command: > run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy networks: traefik_network: external: true volumes: loki-data: driver: local
Erklärung der Docker Compose-Datei:
Loki Service
- image: grafana/loki:latest:
Setzt auf das offizielle Loki-Image von Grafana, das stets aktuell gehalten wird. Dies gewährleistet die neuesten Funktionen und Sicherheitsupdates. - restart: unless-stopped:
Dieser Parameter sorgt dafür, dass der Container automatisch neu startet, es sei denn, er wird manuell gestoppt. Dadurch wird die Betriebszeit maximiert und ungewollte Unterbrechungen werden minimiert. - volumes:
- Hier werden die Konfigurationsdateien in den Container gemountet.
- Zudem speichert es Loki-Daten in einem benannten Volume, was die Persistenz der Daten gewährleistet, auch wenn der Container neu gestartet wird.
- networks:
Loki wird mit dem Traefik-Netzwerk verbunden, was eine reibungslose Integration in eine vorhandene Netzwerkarchitektur ermöglicht. - labels:
- Ermöglicht es Traefik, den Container zu erkennen und nahtlos zu integrieren.
- Routing-Regeln sind so konfiguriert, dass sie basierend auf dem Hostnamen
loki.local
funktionieren. - Der interne Port ist auf 3100 festgelegt, um sicherzustellen, dass Anfragen korrekt geroutet werden.
Alloy Service
- image: grafana/alloy:latest:
Nutzt das neueste offizielle Image für Alloy, um sicherzustellen, dass alle aktuellen Features verfügbar sind. - environment:
- ALLOY_CONFIG: Gibt den Pfad zur Konfigurationsdatei im Container an, was die Anpassung der Konfiguration vereinfacht.
- HOSTNAME: Setzt den Hostnamen für die Vergabe von Labels aus einer Systemvariablen. Sollte diese nicht funktionieren, greift die Fallbacklösung (ändere „raspberrypi“ zu deinem Wunsch-Namen).
- volumes:
- Die Konfigurationsdatei wird gemountet, was dynamische Änderungen erleichtert.
- Log-Verzeichnisse werden im read-only Modus gemountet, um sicherzustellen, dass Logs nicht unbeabsichtigt geändert werden können.
- command:
Spezifiziert den Startbefehl für Alloy, der sowohl einen HTTP-Server betreibt als auch die Datenspeicherung initiiert. - Netzwerke:
Der Container nutzt ein bereits vorhandenes Netzwerk mit dem Namentraefik_network
, wodurch die Konnektivität optimiert wird. - Volumes:
Definiert ein benanntes Volumeloki-data
zur Sicherstellung der Persistenz.
Loki-Konfiguration
Erstelle die Loki-Konfigurationsdatei:
nano loki-config.yml
Füge folgenden Inhalt ein:
auth_enabled: false server: http_listen_port: 3100 log_level: info schema_config: configs: - from: 2023-01-01 store: boltdb-shipper object_store: filesystem schema: v11 index: prefix: index_ period: 24h storage_config: boltdb_shipper: active_index_directory: /loki/index cache_location: /loki/cache shared_store: filesystem cache_ttl: 24h compactor: working_directory: /loki/compactor shared_store: filesystem limits_config: retention_period: 7d # 7 Tage Aufbewahrung, anpassen nach Speicherbedarf ingestion_rate_mb: 4 ingestion_burst_size_mb: 6 chunk_store_config: max_look_back_period: 168h # Entspricht 7 Tagen table_manager: retention_deletes_enabled: true retention_period: 168h
Erklärung der Loki-Konfigurationsdatei
Allgemein
- auth_enabled:
false
– Authentifizierung ist deaktiviert, das heißt, jeder mit Netzwerkzugriff auf Loki kann Daten abfragen oder speichern. Im produktiven Einsatz könnte es sinnvoll sein, die Authentifizierung zu aktivieren. - server:
- http_listen_port:
3100
– Lokis Standard-Port, auf dem es HTTP-Anfragen entgegennimmt. Dies sollte in der Firewall berücksichtigt werden. - log_level:
info
– Legt die Log-Stufe fest. „Info“ bedeutet, dass normale Betriebs-Logs erfasst werden.
- http_listen_port:
Schema-Konfiguration
- schema_config:
- configs: Definiert, wie und wo Logs gespeichert werden, beginnend ab dem 1. Januar 2023.
- store:
boltdb-shipper
– Ein eingebauter Index-Store, der die Verwaltung von Logs vereinfacht. - object_store:
filesystem
– Die Protokolldaten werden im Dateisystem gespeichert. - schema:
v11
– Version des Schemas, sorgt für Kompatibilität und Performance. - index: Definition der Namenskonvention und Aufbewahrungsdauer für Indexe.
- store:
- configs: Definiert, wie und wo Logs gespeichert werden, beginnend ab dem 1. Januar 2023.
Speicherkonfiguration
- storage_config:
- boltdb_shipper: Die Verzeichnisorte für aktiven Index und Cache sind
/loki/index
und/loki/cache
.
- boltdb_shipper: Die Verzeichnisorte für aktiven Index und Cache sind
Compactor
- compactor:
- working_directory: Gibt an, wo der Compactor temporäre Daten speichert, hier
/loki/compactor
. - shared_store: Hier ebenfalls
filesystem
, es speichert kompaktierte Chunks.
- working_directory: Gibt an, wo der Compactor temporäre Daten speichert, hier
Limits-Konfiguration
- limits_config:
- retention_period:
7d
– Logs werden für 7 Tage aufbewahrt. Dies spielt in die Ressourcennutzung hinein. - ingestion_rate_mb und ingestion_burst_size_mb: Bestimmen die Eingaberatenlimits für Logs.
- retention_period:
Chunk-Store-Konfiguration
- max_look_back_period:
168h
– Entspricht 7 Tagen, und gibt die maximale Rückschau auf Logs an.
Table-Manager
- table_manager:
- retention_deletes_enabled:
true
– Aktive Bereinigung basierend auf der Aufbewahrung. - retention_period:
168h
– Entspricht wiederum 7 Tagen und kontrolliert die Aufbewahrung.
- retention_deletes_enabled:
Diese Konfiguration ist optimiert für den Betrieb auf einem Raspberry Pi mit begrenzten Ressourcen.
Sie verwendet das Dateisystem als Speicher und behält Logs für eine Woche.
Alloy-Konfiguration
Erstelle die Alloy-Konfigurationsdatei:
nano alloy-config.yml
Füge den Inhalt der bereitgestellten alloy-config.yml ein:
# Systemd Journal Sammlung discovery.relabel "systemd_journal" { targets = [] rule { source_labels = ["__journal__systemd_unit"] target_label = "unit" } rule { source_labels = ["__journal__hostname"] target_label = "hostname" } rule { source_labels = ["__journal__transport"] target_label = "transport" } rule { source_labels = ["__journal_priority_keyword"] target_label = "level" } } loki.source.journal "systemd_journal" { max_age = "12h0m0s" path = "/var/log/journal" relabel_rules = discovery.relabel.systemd_journal.rules forward_to = [loki.write.grafana_loki.receiver] labels = { job = "systemd", log = "journal", } } # Paket-Management-Logs local.file_match "package" { path_targets = [ {"__path__" = "/var/log/dpkg.log", "log" = "dpkg"}, {"__path__" = "/var/log/apt/history.log", "log" = "apt_history"}, {"__path__" = "/var/log/apt/term.log", "log" = "apt_term"}, ] sync_period = "10s" } loki.source.file "package" { targets = local.file_match.package.targets forward_to = [loki.process.error_detector.receiver] tail_from_end = true } # Fehlererkennungs-Prozessor loki.process "error_detector" { stage.regex { expression = "^(?P<log_level>ERROR|INFO|WARN|DEBUG).*" } stage.labels { values = { "level" = "log_level", } } forward_to = [loki.relabel.add_labels.receiver] } # Label-Hinzufügung loki.relabel "add_labels" { forward_to = [loki.write.package.receiver] rule { target_label = "hostname" replacement = sys.env("HOSTNAME") } rule { target_label = "job" replacement = "package" } } # UniFi-Logs (optional - entfernen, wenn kein UniFi-Controller vorhanden) local.file_match "unifi" { path_targets = [ {"__path__" = "/var/log/unifi/access.log", "log" = "unifi_access"}, {"__path__" = "/var/log/unifi/tasks.log", "log" = "unifi_tasks"}, {"__path__" = "/var/log/unifi/mongod.log", "log" = "unifi_mongod"}, {"__path__" = "/var/log/unifi_package.log", "log" = "unifi_package"}, ] sync_period = "10s" } loki.source.file "unifi" { targets = local.file_match.unifi.targets forward_to = [loki.relabel.unifi_add_labels.receiver] tail_from_end = true } loki.relabel "unifi_add_labels" { forward_to = [loki.write.unifi.receiver] rule { target_label = "hostname" replacement = sys.env("HOSTNAME") } rule { target_label = "job" replacement = "unifi" } } # Loki-Writer-Konfigurationen loki.write "unifi" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } } loki.write "package" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } } loki.write "grafana_loki" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } }
Erklärung der Alloy-Konfigurationsdatei:
Die Alloy-Konfiguration ist umfangreicher und gliedert sich in mehrere Bereiche:
Systemd Journal Sammlung:
discovery.relabel "systemd_journal" { targets = [] rule { source_labels = ["__journal__systemd_unit"] target_label = "unit" } rule { source_labels = ["__journal__hostname"] target_label = "hostname" } rule { source_labels = ["__journal__transport"] target_label = "transport" } rule { source_labels = ["__journal_priority_keyword"] target_label = "level" } } loki.source.journal "systemd_journal" { max_age = "12h0m0s" path = "/var/log/journal" relabel_rules = discovery.relabel.systemd_journal.rules forward_to = [loki.write.grafana_loki.receiver] labels = { job = "systemd", log = "journal", } }
Dieser Abschnitt konfiguriert das Sammeln von Logs aus dem systemd-Journal:
discovery.relabel
: Definiert Regeln zum Umbenennen von Labels aus dem Journal.loki.source.journal
: Konfiguriert die Journal-Quelle:max_age
: Sammelt nur Logs der letzten 12 Stunden.path
: Pfad zum Journal-Verzeichnis.relabel_rules
: Verwendet die oben definierten Regeln.forward_to
: Sendet die Logs an den definierten Empfänger.labels
: Fügt zusätzliche Labels hinzu (job=systemd, log=journal).
Paket-Management-Logs:
local.file_match "package" { path_targets = [ {"__path__" = "/var/log/dpkg.log", "log" = "dpkg"}, {"__path__" = "/var/log/apt/history.log", "log" = "history"}, {"__path__" = "/var/log/apt/term.log", "log" = "term"}, ] sync_period = "10s" } loki.source.file "package" { targets = local.file_match.package.targets forward_to = [loki.process.error_detector.receiver] tail_from_end = true }
Dieser Abschnitt konfiguriert das Sammeln von Paketmanagement-Logs:
local.file_match
: Definiert Datei-Pfade für Paket-Logs (dpkg, apt).loki.source.file
: Konfiguriert die Datei-Quelle:targets
: Verwendet die oben definierten Ziele.forward_to
: Sendet die Logs zur Fehlerverarbeitung.tail_from_end
: Beginnt am Ende der Datei mit dem Lesen.
Fehlererkennungs-Prozessor:
loki.process "error_detector" { stage.regex { expression = "^(?P<log_level>ERROR|INFO).*" } stage.labels { values = { "level" = "log_level", } } forward_to = [loki.relabel.add_labels.receiver] }
Dieser Prozessor erkennt Fehlermeldungen:
stage.regex
: Extrahiert das Log-Level (ERROR oder INFO) mit einem regulären Ausdruck.stage.labels
: Fügt das extrahierte Log-Level als Label hinzu.forward_to
: Leitet die verarbeiteten Logs zur Label-Hinzufügung weiter.
Label-Hinzufügung:
loki.relabel "add_labels" { forward_to = [loki.write.package.receiver] rule { target_label = "hostname" replacement = sys.env("HOSTNAME") } rule { target_label = "job" replacement = "package" } }
Dieser Abschnitt fügt weitere Labels hinzu:
target_label = "hostname"
: Setzt den Hostnamen aus der Umgebungsvariable.target_label = "job"
: Setzt das Job-Label auf „package“.
UniFi-Logs-Sammlung: (nur für Unifi Besitzer interessant, bei denen die Controller-Software auf dem Raspberry läuft)
local.file_match "unifi" { path_targets = [ {"__path__" = "/var/log/unifi/access.log", "log" = "unifi_access"}, {"__path__" = "/var/log/unifi/tasks.log", "log" = "unifi_tasks"}, {"__path__" = "/var/log/unifi/mongod.log", "log" = "unifi_mongod"}, {"__path__" = "/var/log/unifi_package.log", "log" = "unifi_package"}, ] sync_period = "10s" }
Dieser Abschnitt konfiguriert das Sammeln von UniFi-Logs, ähnlich wie die Paket-Logs.
Loki-Schreibkonfiguration:
loki.write "unifi" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } } loki.write "package" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } } loki.write "grafana_loki" { endpoint { url = "http://loki_traefik:3100/loki/api/v1/push" } }
Diese Abschnitte definieren, wohin die Logs gesendet werden:
endpoint
: Definiert den Loki-Endpunkt (URL), an den die Logs gesendet werden.- Bei dieser Konfiguration werden die Logs an den lokalen Loki-Container gesendet.
Die Alloy-Konfiguration ist modular aufgebaut und ermöglicht es, verschiedene Log-Quellen zu definieren und zu verarbeiten, bevor sie an Loki gesendet werden.
Container starten
Nachdem alle Konfigurationsdateien erstellt wurden, starten wir die Container:
cd ~/docker/logging docker compose up -d
Überprüfe, ob die Container erfolgreich gestartet wurden:
docker ps | grep -E 'loki|alloy'
Du solltest zwei laufende Container sehen: loki_traefik
und alloy_traefik
.
Überprüfen der Logs
Überprüfe die Logs beider Container, um sicherzustellen, dass sie fehlerfrei gestartet wurden:
# Loki-Logs prüfen docker logs loki_traefik | grep -E 'error|fail|ready' # Alloy-Logs prüfen docker logs alloy_traefik | grep -E 'error|fail|running'
Achte auf Fehlermeldungen oder Warnungen. Im Normalfall sollten beide Dienste ohne kritische Probleme starten.
Konfiguration von Grafana und Verwendung des Dashboards
Nachdem Loki und Alloy erfolgreich installiert sind, richten wir Grafana ein, um die gesammelten Logs anzuzeigen. Ich zeige dir, wie du das mitgelieferte Dashboard importierst und optimale Abfragen für dein Log-Monitoring erstellst.
Loki als Datenquelle in Grafana hinzufügen
- Öffne Grafana unter http://grafana.local
- Navigiere zu „Configuration“ > „Data Sources“ (oder direkt zu http://grafana.local/connections/datasources)
- Klicke auf „Add data source“
- Wähle „Loki“ aus der Liste
- Konfiguriere folgende technische Parameter:
- Name:
Loki
- URL:
http://loki_traefik:3100
(bei gleichem Docker-Netzwerk) oderhttp://loki.local
(über Traefik) - Access:
Server (default)
- HTTP Method:
GET
- TLS/SSL Auth: Deaktiviert
- Skip TLS Verify: Aktiviert für lokale Entwicklung
- Forward OAuth Identity: Deaktiviert
- Timeout:
30
(Standard)
- Name:
- Erweiterte HTTP-Einstellungen: Belasse auf Standardwerten
- Klicke auf „Save & Test“
Bei erfolgreicher Verbindung erscheint die Meldung „Data source connected and labels found“.
Dashboard importieren
Ich habe ein einfaches Dashboard speziell für Raspberry Pi Log-Monitoring erstellt.
So importierst du es:
- Navigiere zu „Dashboards“ > „+ Import“ (oder direkt zu http://grafana.local/dashboard/import)
- Verwende entweder:
- Die Dashboard-ID: 23134
- Oder klicke auf „Upload JSON file“ und wähle die heruntergeladene JSON-Datei (Rechtsklick, Speichern)
- Konfiguriere:
- Name:
Raspberry Pi Log Monitoring
- Folder:
Logging
(oder erstelle einen neuen Ordner) - Loki data source: Wähle die eben erstellte
Loki
-Datenquelle
- Name:
- Klicke auf „Import“
Das Dashboard sollte nun verfügbar sein und direkt deine Logs anzeigen, nachdem Alloy ausreichend Zeit hatte, Logs zu sammeln.
Erklärung des Dashboards
Das importierte Dashboard bietet eine umfassende Übersicht über deine Systemlogs mit folgenden Bereichen:
Übersichtsbereich:
- Log-Volumina nach Schweregrad (INFO, WARN, ERROR)
- Zeitreihen der Log-Aktivitäten
- Top-Log-Produzenten nach Host/Service
Detailpanels:
- Logs nach Schweregrad gefiltert
- Suchfunktion für spezifische Log-Inhalte
- Drill-down-Möglichkeiten für Detailanalysen
Logs nach Systemkomponenten:
- Systemd-Logs (Kernel, Dienste)
- Paket-Management (apt, dpkg)
- Optional: UniFi-Controller (falls konfiguriert)
Anpassung des Dashboards
Das Dashboard kann nach Bedarf angepasst werden:
- Klicke auf das Zahnrad-Symbol oben rechts, um das Dashboard zu bearbeiten
- Einzelne Panels können durch Klicken auf den Panel-Titel und „Edit“ angepasst werden
- Um ein neues Panel hinzuzufügen, klicke auf „+ Add panel“ oben rechts
- Speichere Änderungen mit „Save“ in der oberen rechten Ecke
Praktische Anwendungen und Beispiele
Hier sind einige praktische Anwendungsfälle für dein neues Logging-System direkt in Grafana.
Du kannst die Abfragen zum Testen bei „Entdecken -> Queries -> Code“ eingeben:
Überwachung von System-Updates
Mit unserem Setup werden automatisch alle Paketoperationen überwacht. So kannst du feststellen, wann und welche Pakete installiert oder aktualisiert wurden:
{job="package"} |= "upgrade" or {job="package"} |= "install"
Diese Abfrage in Grafana zeigt dir alle Paketinstallationen und -upgrades.
Erkennung von Systemabstürzen und -neustarts
Systemabstürze und unerwartete Neustarts hinterlassen Spuren im systemd-Journal:
{job="systemd"} |= "Startup finished" | json | line_format "System startup completed in {{.MESSAGE}}"
Diese Abfrage hilft, Bootzeiten zu identifizieren und nach unerwarteten Neustarts zu suchen.
Fehleranalyse für UniFi-Controller (falls vorhanden)
Wenn du UniFi-Geräte in deinem Netzwerk hast, sammelt Alloy bereits die UniFi-Controller-Logs:
{job="unifi"} |~ "(?i)error|fail|exception|terminated"
Diese Abfrage zeigt alle Fehler im UniFi-Controller, was bei der Fehlersuche in deinem Netzwerk hilft.
Sicherheitsrelevante Ereignisse überwachen
{job="systemd"} |~ "(?i)authentication|sudo|permission|authorized|refused"
Diese Abfrage findet sicherheitsrelevante Ereignisse wie Authentifizierungsversuche oder Berechtigungsänderungen.
Benachrichtigungen für kritische Ereignisse einrichten
Grafana-Benachrichtigungen können auf Basis deiner Log-Daten konfiguriert werden:
- Navigiere zu „Alerting“ > „Alert rules“ > „New alert rule“
- Konfiguriere eine Regel mit:
- Data source:
Loki
- Query:
sum(count_over_time({level="ERROR"} [5m])) > 5
- Name:
Excessive Error Detection
- Folder:
Logging
- Evaluation interval:
1m
- For:
5m
(Zeitraum, für den die Bedingung erfüllt sein muss)
- Data source:
- Konfiguriere Benachrichtigungskanäle nach Bedarf (Email, Slack, Discord, etc.)
Diese Regel löst einen Alarm aus, wenn mehr als 5 Fehler innerhalb von 5 Minuten auftreten.
Best Practices für Alloy-Konfigurationen
Modularität:
- Teile deine Konfiguration in logische Gruppen (z.B. nach Log-Quelle)
- Benenne Komponenten sinnvoll (
nginx_parser
stattparser1
)
Ressourcennutzung:
- Setze
tail_from_end = true
für neue Deployments, um nicht sofort alle historischen Logs zu verarbeiten - Verwende
exclude
-Direktiven, um unnötige Logs zu filtern
Labels vs. Loginhalt:
- Extrahiere häufig abgefragte Werte als Labels (z.B.
level
,service
) - Behalte die Detailinformationen im Logtext
- Beachte: Zu viele Labels erhöhen den Speicherbedarf in Loki
Effiziente Regex:
- Verwende benannte Capture-Gruppen (
(?P<name>pattern)
) - Optimiere Ausdrücke für Leistung (vermeide Backtracking)
- Teste deine Regex mit Tools wie regex101.com
Sicherheit:
- Filtere sensible Informationen (Passwörter, Tokens) vor dem Senden an Loki
stage.replace { expression = "(password|token|secret)=\\S+" replace = "${1}=REDACTED" }
Durch das Verständnis dieser Grundkonzepte kannst du deine Alloy-Konfiguration erweitern und anpassen, um verschiedene Log-Quellen zu integrieren und wertvolle Erkenntnisse aus deinen Logs zu gewinnen.
Mein Fazit
Grafana Loki und Alloy bieten ein leistungsfähiges, aber ressourceneffizientes Logging-System für den Raspberry Pi. Die modulare Konfiguration von Alloy ermöglicht es, den Log-Sammelprozess genau an deine Bedürfnisse anzupassen – von einfachen Datei-Logs bis hin zu komplexer Verarbeitung und Anreicherung.
Mit dem bereitgestellten Dashboard erhältst du sofort einen umfassenden Überblick über den Zustand deines Systems. Die Integration mit Pi-hole für die DNS-Verwaltung vereinfacht zudem den Zugriff auf deine Services im Heimnetzwerk.
Für weitere Anpassungen kannst du die vorgestellten Konzepte und Beispiele nutzen, um neue Log-Quellen hinzuzufügen oder die bestehende Verarbeitung zu optimieren.
Du wirst hier einen groben Überblick finden.
Allerdings biete ich dir auch noch etwas mehr Support an:
- Du benötigst persönlichen Support
- Du möchtest von Beginn an Unterstützung bei deinem Projekt
- Du möchtest ein hier vorgestelltes Plugin durch mich installieren und einrichten lassen
- Du würdest gerne ein von mir erstelltes Script etwas mehr an deine Bedürfnisse anpassen
Für diese Punkte und noch einiges mehr habe ich einen limitierten
VIP-Patreon Tarif
eingerichtet. Falls er dir dort zurzeit nicht angeboten wird,
kontaktiere mich bitte über Discord und wir finden eine Lösung!