Raspberry Pi mit Prometheus und Grafana überwachen
Teil 7 von 7 der Reihe Homelab auf dem Raspberry Pi

Management Summary
Überwachung macht den Zustand eines Raspberry Pi im Zeitverlauf sichtbar, statt erst beim Ausfall eines Dienstes. Prometheus sammelt Messwerte etwa zu Temperatur und Auslastung; Grafana stellt diese übersichtlich als Diagramme dar. Bei kleinen Serverinstallationen hilft das, Überhitzung, Stromprobleme oder steigende Belastung zu erkennen. Warnungen lenken den Blick auf ungewöhnliche Zustände, erklären aber nicht automatisch die Ursache. Auch fehlende oder alte Werte sind wichtig, denn ausbleibende Meldungen beweisen keinen gesunden Betrieb.
Inhalt
Auslastung beobachten, ohne Ausfälle vorherzusagen
Prometheus speichert Messwerte im Zeitverlauf, Grafana stellt diese Werte dar. Auf dem Raspberry Pi stellt node_exporter Linux-Messwerte zum Abruf bereit. Ein kleines Sammelskript ergänzt Temperatur und Warnmeldungen der Firmware, also der eingebauten Gerätesteuerung. Monitoring hilft bei der Untersuchung von Engpässen. Ein Dashboard verhindert keine Überhitzung, repariert kein Netzteil und sagt kein Ausfalldatum eines Speichermediums voraus.
Das Beispiel richtet sich an einen getrennten, neuen Raspberry-Pi-OS-Aufbau mit Python 3, Docker Engine und Compose. Bestehende Konten, Collector-Verzeichnisse und Dienste müssen vor der Einrichtung abgeglichen werden. Die Host-Konfiguration benötigt Verwaltungsrechte. Alle Netzwerkdienste lauschen nachfolgend auf der lokalen Adresse 127.0.0.1, genannt Loopback. Andere Geräte im Netz können nicht direkt zugreifen; der Browserzugriff erfolgt über einen verschlüsselten SSH-Tunnel zum Pi.

1. Firmwarewerte mit Fehlerbehandlung erfassen
Die Datei rpi-hardware-metrics.py liest ausschließlich Temperatur und Drosselungsstatus. Jeder Aufruf besitzt ein Zeitlimit; unerwartete Ausgaben brechen den Lauf ab. Bei Fehlern bleibt die vorherige Datei erhalten. Der Zeitstempel des letzten Erfolgs unterscheidet alte von neuen Messwerten; ein erfolgreicher HTTP-Abruf allein erkennt einen stehen gebliebenen Collector nicht.
#!/usr/bin/env python3
import os
import re
import subprocess
import sys
import tempfile
import time
from pathlib import Path
FLAGS = ("undervoltage", "frequency_capped", "throttled", "soft_temperature_limit")
def read_value(argument):
return subprocess.run(
["/usr/bin/vcgencmd", argument], check=True,
capture_output=True, text=True, timeout=5
).stdout.strip()
def collect(reader=read_value):
temperature = re.fullmatch(r"temp=(-?[0-9]+(?:[.][0-9]+)?)'C", reader("measure_temp"))
throttle = re.fullmatch(r"throttled=0x([0-9a-fA-F]{1,8})", reader("get_throttled"))
if temperature is None or throttle is None:
raise ValueError("Unexpected vcgencmd output")
mask = int(throttle.group(1), 16)
lines = [
"# HELP rpi_soc_temperature_celsius SoC temperature",
"# TYPE rpi_soc_temperature_celsius gauge",
"rpi_soc_temperature_celsius " + temperature.group(1),
"# HELP rpi_soc_throttled_bitmask Complete firmware bitmask",
"# TYPE rpi_soc_throttled_bitmask gauge",
f"rpi_soc_throttled_bitmask {mask}",
"# HELP rpi_hardware_flag Firmware flag; current or since boot",
"# TYPE rpi_hardware_flag gauge",
]
for state, offset in (("current", 0), ("since_boot", 16)):
for bit, name in enumerate(FLAGS):
value = (mask >> (offset + bit)) & 1
lines.append(f'rpi_hardware_flag{{state="{state}",flag="{name}"}} {value}')
lines += [
"# HELP rpi_collector_last_success_timestamp_seconds Last successful collection",
"# TYPE rpi_collector_last_success_timestamp_seconds gauge",
f"rpi_collector_last_success_timestamp_seconds {time.time():.3f}",
]
return "\n".join(lines) + "\n"
def publish(directory, content):
directory = Path(directory)
fd, temporary = tempfile.mkstemp(prefix=".rpi-", suffix=".tmp", dir=directory)
try:
with os.fdopen(fd, "w", encoding="utf-8") as output:
output.write(content)
os.fchmod(output.fileno(), 0o644)
os.replace(temporary, directory / "rpi_metrics.prom")
finally:
if os.path.exists(temporary):
os.unlink(temporary)
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("Usage: rpi-hardware-metrics.py TEXTFILE_DIRECTORY")
publish(sys.argv[1], collect())Aktuelle und seit dem Start aufgezeichnete Flags erhalten getrennte Labels. Beispielsweise dokumentiert 0x50000 frühere Unterspannung und Drosselung, ohne einen aktuell anhaltenden Zustand zu behaupten. Minütliche Abfragen können kurze aktuelle Zustände verpassen. Historische Flags bewahren einen Teil dieser Hinweise, liefern jedoch keinen Ereigniszeitpunkt. Unbekannte zukünftige Bits bleiben in der vollständigen Bitmaske sichtbar.
Die Kernspannung fehlt bewusst. Eine interne Versorgungsschiene entspricht weder der USB-Eingangsspannung noch einer Diagnose eines defekten Netzteils. Der Pi 5 liefert separate Messwerte des Chips zur Stromversorgung (PMIC), etwa über vcgencmd pmic_read_adc EXT5V_V; eine Erweiterung benötigt modellspezifisches Parsing und Rechteprüfungen.
2. Host-Collector und Timer einrichten
Die Einrichtungsbefehle setzen die drei gezeigten Dateien im Arbeitsverzeichnis und eine vorhandene Gruppe video voraus. rpi-metrics ist ein neues Dienstkonto ohne Anmeldung; ein bestehendes Konto wird geprüft und nicht erneut angelegt. Raspberry Pi OS muss /usr/bin/vcgencmd bereitstellen. Hardwarezugriff hängt vom installierten Betriebssystem ab und muss unter dem Dienstkonto getestet werden.
sudo apt update
sudo apt install prometheus-node-exporter python3
sudo useradd --system --user-group --groups video --no-create-home --shell /usr/sbin/nologin rpi-metrics
sudo install -d -o rpi-metrics -g rpi-metrics -m 755 /var/lib/node_exporter/textfile_collector
sudo install -d -m 755 /usr/local/libexec
sudo install -m 755 rpi-hardware-metrics.py /usr/local/libexec/rpi-hardware-metrics.py
sudo install -m 644 rpi-collector.service rpi-collector.timer /etc/systemd/system/Die Datei rpi-collector.service enthält:
[Unit]
Description=Collect Raspberry Pi firmware metrics
[Service]
Type=oneshot
User=rpi-metrics
SupplementaryGroups=video
ExecStart=/usr/bin/python3 /usr/local/libexec/rpi-hardware-metrics.py /var/lib/node_exporter/textfile_collector
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/node_exporter/textfile_collectorDie Datei rpi-collector.timer enthält:
[Unit]
Description=Collect Raspberry Pi firmware metrics periodically
[Timer]
OnBootSec=30s
OnUnitActiveSec=60s
AccuracySec=1s
[Install]
WantedBy=timers.targetsudo -u rpi-metrics /usr/bin/vcgencmd measure_temp und der entsprechende Aufruf für get_throttled prüfen den tatsächlichen Zugriff. Der Exporter benötigt Leserechte auf Verzeichnis und erzeugte Datei. Das installierte Skript gehört root; das Dienstkonto schreibt nur in das Collector-Ausgabeverzeichnis.
Beim Debian-Paket zeigt systemctl cat prometheus-node-exporter, wie Startargumente eingelesen werden. Bei Verwendung von /etc/default/prometheus-node-exporter benötigt das vorhandene ARGS zusätzlich --collector.textfile.directory=/var/lib/node_exporter/textfile_collector und --web.listen-address=127.0.0.1:9100. Andere vorhandene Optionen bleiben erforderlich; doppelte Optionen für das Verzeichnis oder die Empfangsadresse müssen aufgelöst werden. Maßgeblich ist die Konfiguration des tatsächlich installierten Pakets.
Nach der Konfiguration aktivieren sudo systemctl restart prometheus-node-exporter, sudo systemctl daemon-reload und sudo systemctl enable --now rpi-collector.timer die Dienste. sudo systemctl start rpi-collector.service startet einen ersten Lauf. Fehler bleiben über journalctl -u rpi-collector.service sichtbar; wiederholte Einrichtung hängt keine doppelten Cron-Einträge an.
3. Messwerte mit Prometheus speichern
Die folgende compose.yaml verwendet unter Linux Host-Netzwerk, damit die Container-Loopback-Adresse den Host-Exporter erreicht. Ausdrücklich gesetzte lokale Empfangsadressen begrenzen den direkten Zugriff auf Prometheus und Grafana auf den Pi. Eine geschützte .env definiert getestete ARM-kompatible Image-Referenzen für PROMETHEUS_IMAGE und GRAFANA_IMAGE sowie ein eigenes GRAFANA_ADMIN_PASSWORD für die Ersteinrichtung. Eine bestehende Grafana-Datenbank behält das bereits eingerichtete Administratorpasswort.
services:
prometheus:
image: ${PROMETHEUS_IMAGE:?set tested prom/prometheus release}
network_mode: host
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=7d
- --web.listen-address=127.0.0.1:9090
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
- prometheus-data:/prometheus
grafana:
image: ${GRAFANA_IMAGE:?set tested grafana/grafana release}
network_mode: host
restart: unless-stopped
environment:
GF_SERVER_HTTP_ADDR: 127.0.0.1
GF_SERVER_HTTP_PORT: "3000"
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:?set initial admin password}
GF_AUTH_ANONYMOUS_ENABLED: "false"
volumes:
- grafana-data:/var/lib/grafana
volumes:
prometheus-data:
grafana-data:Die Datei prometheus.yml im selben Ordner enthält:
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- /etc/prometheus/alerts.yml
scrape_configs:
- job_name: raspberry_pi
static_configs:
- targets: ["127.0.0.1:9100"]Sieben Tage Aufbewahrung sind ein Beispiel und keine Begrenzung des Speicherplatzverbrauchs. Benannte Volumes erhalten Daten beim Neuerstellen der Container. Freier Speicher, Schreiblast und Sicherungen benötigen eigene Überwachung. Ein Abruf alle 15 Sekunden erhöht nicht die ungefähr minütliche Messfrequenz des Collectors.
4. Alarmregeln und Benachrichtigungen trennen
Die folgende alerts.yml prüft Messwerte und die Funktionsfähigkeit der Erfassung. Die Schwelle 75 °C ist ein beispielhafter Betriebswert und keine universelle Hardwaregrenze. Die Regel für fehlende Reihen setzt diesen Job mit genau einem Ziel voraus; mehrere Hosts benötigen eine zielbezogene Ausfallerkennung.
groups:
- name: raspberry_pi
rules:
- alert: PiExporterDown
expr: up{job="raspberry_pi"} == 0
for: 2m
- alert: PiCollectorStale
expr: time() - rpi_collector_last_success_timestamp_seconds{job="raspberry_pi"} > 180
for: 1m
- alert: PiCollectorMissing
expr: absent(rpi_collector_last_success_timestamp_seconds{job="raspberry_pi"})
for: 2m
- alert: PiTextfileError
expr: node_textfile_scrape_error{job="raspberry_pi"} == 1
for: 1m
- alert: PiTemperatureHigh
expr: rpi_soc_temperature_celsius{job="raspberry_pi"} > 75
for: 5m
- alert: PiCurrentFirmwareWarning
expr: rpi_hardware_flag{job="raspberry_pi",state="current"} == 1docker compose config --quiet prüft Compose. promtool check config und promtool check rules aus dem gewählten Image validieren die Prometheus-Dateien vor dem Start. docker compose up -d startet den Aufbau. Die Regeln zeigen ausstehende oder aktive Alarme in Prometheus; E-Mail- oder Push-Nachrichten entstehen erst nach Einrichtung und Prüfung einer Alertmanager-Anbindung. Auch eine Grafana-Panelschwelle allein ist keine Benachrichtigungsregel.
Auf dem Arbeitsplatzrechner leitet ssh -N -L 3000:127.0.0.1:3000 -L 9090:127.0.0.1:9090 ACCOUNT@PI_ADDRESS die lokalen Browserports weiter. Die Platzhalter bezeichnen das tatsächliche SSH-Konto und die Pi-Adresse. Grafana öffnet unter http://127.0.0.1:3000; die Prometheus-Datenquelle verwendet http://127.0.0.1:9090, weil beide Container das Host-Netz teilen.
Sinnvolle Panels und deren Grenzen
rpi_soc_temperature_celsius: abgetastete SoC-Temperatur.rpi_hardware_flag{state="current"}: aktuelle Firmware-Flags;state="since_boot"zeigt aufgezeichnete Vorfälle.100 * rate(node_disk_io_time_seconds_total[5m]): prozentuale Geräte-Beschäftigungszeit mit Grenzen der Kernel-Zeitrechnung. Das ist weder Flash-Verschleiß noch Anfragelatenz.100 * node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes: verfügbarer RAM-Anteil, keine Rate pro Sekunde.
Eine passende Geräteauswahl vermeidet irreführende Vergleiche physischer Laufwerke und virtueller Geräte. Speicherverschleiß benötigt unterstützte SMART-/NVMe- oder Hersteller-Gesundheitswerte; viele SD-Karten geben kaum brauchbare Verschleißdaten aus. Hohe Beschäftigungszeit allein identifiziert keinen verschlissenen Controller.
Fragen und Antworten
Wie lässt sich der Datenweg ohne Speicher-Stresstest prüfen?
Exporter-Erreichbarkeit, up, node_textfile_scrape_error, Alter des letzten Erfolgs und Timer-Protokolle bilden die erste Kontrolle. In einer getrennten Testumgebung sollte ein angehaltener Timer einen Veraltungsalarm auslösen; fehlerhafte synthetische Befehlsantworten müssen die letzte gültige Datei unverändert lassen. Ein intensiver zufälliger Schreibtest ist dafür unnötig.
Identifiziert ein Unterspannungs-Flag die Ursache?
Nein. Das Flag meldet einen erkannten Zustand. Netzteil, Kabel, Anschlüsse und Peripherielast benötigen eine getrennte Untersuchung. Temperatur und Drosselung beschreiben Symptome; weder Diagramm noch Flag garantieren die Vermeidung eines Ausfalls.
Bezeichnet 127.0.0.1 immer den Host?
Nein. Gewöhnliche Bridge-Container besitzen eigene Loopback-Schnittstellen. Das Beispiel verwendet ausdrücklich Host-Netzwerk. Ein anderer Aufbau benötigt eine erreichbare Exporter-Adresse und eine dazu passende Grafana-Datenquelle.
Quellen
- Prometheus-Dokumentation
- Grafana-Dokumentation
- vcgencmd: Temperatur, Statusbits, Kernspannung und Pi-5-Stromversorgung
- Node Exporter: Hostmesswerte und atomarer Dateiaustausch
- Prometheus: Alarmaktivierung und Wartezeiten
- Linux: Laufwerksauslastung und weitere E/A-Statistiken
- Grafana: lokale Empfangsadresse und Umgebungsvariablen
- PromQL: absent und time
- Prometheus: Empfangsadresse und Aufbewahrungsoptionen
Homelab auf dem Raspberry Pi
- Raspberry Pi 4 und 5: Vom SSD-Laufwerk booten über den Bootloader
- USV für Raspberry Pi: fünf Lösungen und Auswahlkriterien
- Lokales CI/CD für den Raspberry Pi: Automatisierung von Docker-Compose-Deployments
- Docker-Compose-Heimserver: Traefik, TLS und Update-Prüfung
- Jellyfin auf Raspberry Pi 5: Direct Play und Grenzen der Transkodierung
- Raspberry Pi als gehärtetes WireGuard-VPN-Gateway mit Split-Tunneling
- Raspberry Pi mit Prometheus und Grafana überwachen