Bare-Metal Performance Diagnostics: Prometheus & Grafana Dashboard für Raspberry Pi
Teil 7 von 7 der Reihe Homelab auf dem Raspberry Pi

Inhalt
Architektur-Überblick: Schwachstellen von Einplatinencomputern
Einplatinencomputer mit ARM-Architektur wie der Raspberry Pi 4 und 5 operieren unter engen thermischen und I/O-spezifischen Grenzen. Dauerhafte Container-Workloads, häufige Schreibzyklen von Datenbanken und hoher Netzwerkdurchsatz führen regelmäßig zu unbemerkter Hardware-Degradation. Hohe SoC-Temperaturen aktivieren das dynamische Thermal-Throttling durch die Broadcom-Firmware, was die ARM-Taktfrequenz senkt, ohne dass explizite Fehlermeldungen in den Protokollen von Benutzeranwendungen erscheinen. Ebenso führen kontinuierliche zufällige Schreiboperationen auf MicroSD-Karten oder über USB angebundenen SSDs zur Erschöpfung von Flash-Blöcken, I/O-Engpässen und letztendlich zu korrupten Dateisystemen.
Die Implementierung einer Bare-Metal-Performance-Diagnose-Pipeline mit Prometheus und Grafana verwandelt intransparente Hardware-Zustände in präzise Zeitreihenmetriken. Durch die Kombination des standardmäßigen node_exporter-Daemons mit einem spezialisierten Textfile-Collector-Skript lassen sich kritische Raspberry-Pi-Indikatoren – darunter SoC-Kerntemperaturen, Unterspannungs-Flags, Taktfrequenzen, RAM-Sättigung und Speicher-I/O-Wartezeiten – alle 15 Sekunden abfragen (die per vcgencmd ermittelten Werte aktualisiert das eingeplante Collector-Skript einmal pro Minute), auf Schwellenwertverletzungen prüfen und in Echtzeit-Dashboards visualisieren.

vcgencmd-Werte gelangen über Textfile-Collector, Node Exporter und Prometheus bis nach Grafana — und lösen oberhalb von 75 °C oder bei gesetzter Throttling-Bitmask einen Alarm aus.Schritt-für-Schritt-Implementierungsanleitung
Schritt 1: Deployment des Node Exporters und des Textfile-Collectors
Zur Erfassung der standardmäßigen Linux-Kernel-Telemetrie sowie proprietärer Broadcom-Hardwarestatistiken wird node_exporter installiert und ein dediziertes Verzeichnis für eigene Metrik-Dateien eingerichtet:
apt update && apt install -y prometheus-node-exporter
mkdir -p /var/lib/node_exporter/textfile_collector
chmod 755 /var/lib/node_exporter/textfile_collector
Erstellung eines Shell-Skripts unter /opt/scripts/rpi-hardware-metrics.sh, das SoC-Temperatur, Kernspannung und Hardware-Throttling-Flags mittels vcgencmd extrahiert:
#!/usr/bin/env bash
# /opt/scripts/rpi-hardware-metrics.sh
# Extrahiert Bare-Metal-SoC-Metriken für den Prometheus-Textfile-Collector
TEXTFILE_DIR="/var/lib/node_exporter/textfile_collector"
TMP_FILE="$TEXTFILE_DIR/rpi_metrics.prom.$$"
FINAL_FILE="$TEXTFILE_DIR/rpi_metrics.prom"
# 1. CPU-Kerntemperatur extrahieren (Grad Celsius)
TEMP_C=$(vcgencmd measure_temp | grep -oE '[0-9]+([.][0-9]+)?')
echo "# HELP rpi_soc_temperature_celsius Broadcom SoC Core Temperature" > "$TMP_FILE"
echo "# TYPE rpi_soc_temperature_celsius gauge" >> "$TMP_FILE"
echo "rpi_soc_temperature_celsius $TEMP_C" >> "$TMP_FILE"
# 2. SoC-Kernspannung extrahieren (Volt)
VOLT_V=$(vcgencmd measure_volts core | grep -oE '[0-9]+([.][0-9]+)?')
echo "# HELP rpi_soc_core_voltage_volts Broadcom SoC Core Voltage" >> "$TMP_FILE"
echo "# TYPE rpi_soc_core_voltage_volts gauge" >> "$TMP_FILE"
echo "rpi_soc_core_voltage_volts $VOLT_V" >> "$TMP_FILE"
# 3. Throttling-Hexcode als Integer-Bitmaske extrahieren
THROTTLE_HEX=$(vcgencmd get_throttled | cut -d'=' -f2)
THROTTLE_DEC=$((THROTTLE_HEX))
echo "# HELP rpi_soc_throttled_bitmask Bitmask representing under-voltage or thermal throttling flags" >> "$TMP_FILE"
echo "# TYPE rpi_soc_throttled_bitmask gauge" >> "$TMP_FILE"
echo "rpi_soc_throttled_bitmask $THROTTLE_DEC" >> "$TMP_FILE"
mv "$TMP_FILE" "$FINAL_FILE"
Skript ausführbar machen und die Ausführung minütlich über crontab einplanen:
chmod +x /opt/scripts/rpi-hardware-metrics.sh
(crontab -l 2>/dev/null; echo "* * * * * /bin/bash /opt/scripts/rpi-hardware-metrics.sh >/dev/null 2>&1") | crontab -
Schritt 2: Neukonfiguration des systemd-Dienstes des Node Exporters
Anpassung der systemd-Konfiguration des node_exporter, damit Metriken aus dem benutzerdefinierten Textfile-Verzeichnis eingelesen werden:
# /etc/default/prometheus-node-exporter
ARGS="--collector.textfile.directory=/var/lib/node_exporter/textfile_collector --collector.filesystem.mount-points-exclude='^/(dev|proc|sys|run)($|/)'"
Neustart des Dienstes zur Übernahme der Flags: systemctl restart prometheus-node-exporter.
Schritt 3: Konfiguration des Prometheus-Scrapers
Bereitstellung von Prometheus via Docker Compose mit network_mode: host und Konfiguration eines 15-Sekunden-Scrape-Intervalls auf das lokale Node-Exporter-Ziel:
# /opt/containers/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'raspberry_pi_baremetal'
static_configs:
- targets: ['127.0.0.1:9100']
labels:
instance: 'rpi5-homelab'
Schritt 4: Grafana-Deployment und Import von Bare-Metal-Panels
Start von Grafana via Docker Compose, ebenfalls mit network_mode: host, Einbindung der Prometheus-Datenbank (http://127.0.0.1:9090) als Standard-Datenquelle und Erstellung von Dashboard-Panels auf Basis folgender PromQL-Abfragen:
- SoC-Kerntemperatur-Panel:
rpi_soc_temperature_celsius(Alarm-Schwellenwert konfiguriert bei > 75 °C). - Unterspannungs- & Throttling-Alarm:
rpi_soc_throttled_bitmask > 0(Signalisiert unzureichende Netzteile oder Überhitzung, aktuell oder seit dem letzten Start; bleibt bis zum Neustart aktiv). - Speicher-I/O-Auslastung:
rate(node_disk_io_time_seconds_total[1m]) * 100(Erkennt Flash-Controller-Engpässe und abgenutzte Speicherblöcke). - Verfügbarkeitsrate des Arbeitsspeichers:
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100.
Schritt 5: Qualitätssicherung und Stress-Tests
Zur Verifikation, dass die Telemetrie-Pipeline Hardware-Auslastungen korrekt protokolliert, müssen Lasttests durchgeführt werden:
- Validierung der I/O-Last: Ausführung eines intensiven Schreibtests mit
fio(z. B.fio --name=test --ioengine=libaio --rw=randwrite --bs=4k --size=1G) und Kontrolle, ob das Grafana-I/O-Wait-Panel Echtzeit-Latenzspitzen anzeigt. - Simulation von Thermal-Throttling: Auslastung aller ARM-CPU-Kerne über
stress-ng --cpu 4 --timeout 120sbei gleichzeitiger Überwachung vonrpi_soc_temperature_celsiusin Prometheus, um die präzise Temperaturmessung bis zum Einsetzen der Kühllüfter zu bestätigen. - Audit des Textfile-Parsings: Ausführung von
curl -s http://127.0.0.1:9100/metrics | grep rpi_im Terminal zur Verifikation, dass eigene Spannungs- und Throttling-Metriken fehlerfrei und ohne Syntax-Probleme bereitgestellt werden.
Zusammenfassung und resultierender Mehrwert
Was sich damit erreichen lässt: Der Aufbau einer autonomen Bare-Metal-Hardware-Diagnose-Pipeline auf dem Raspberry Pi mittels Prometheus-Scraper, eigenen SoC-Textfile-Collectors und Grafana-Dashboards.
Resultierender Mehrwert:
- Früherkennung von Speicherausfällen: Die kontinuierliche Überwachung von I/O-Wartezeiten und Flash-Verschleiß ermöglicht den präventiven Austausch abgenutzter SD-Karten oder SSDs vor einem Dateisystemschaden.
- Vermeidung von Thermal-Throttling: Die Echtzeit-Sichtbarkeit von SoC-Temperaturen und Throttling-Bitmasken garantiert, dass containerisierte Dienste dauerhaft mit maximaler Taktfrequenz operieren.
- Qualitätskontrolle der Stromversorgung: Die sofortige Protokollierung von Unterspannungs-Flags (Bit 0,
bitmask 0x1) identifiziert defekte USB-C-Netzteile oder übermäßigen Stromverbrauch angeschlossener Peripheriegeräte vor Hardware-Abstürzen.
Fragen und Antworten
Warum bleibt der Throttling-Alarm nach einem einzigen Vorfall bis zum nächsten Neustart aktiv?
Weil get_throttled zwei Arten von Bits liefert. Die unteren Bits beschreiben den Zustand im Augenblick, darunter Bit 0 für Unterspannung und Bit 2 für Drosselung. Die Bits ab 16 halten fest, dass dasselbe seit dem Start irgendwann aufgetreten ist, und bleiben gesetzt, bis der Raspberry Pi neu startet. Ein kurzer Spannungseinbruch am Morgen ergibt deshalb etwa 0x50000 (Unterspannung und Drosselung aufgetreten), dezimal 327680, und dieser Wert bleibt für den Rest des Tages größer als null.
Für die Auswertung lohnt es sich, beides zu trennen. PromQL kennt den Operator %, und rpi_soc_throttled_bitmask % 16 > 0 prüft nur die vier unteren Bits, also den aktuellen Zustand; rpi_soc_throttled_bitmask >= 65536 meldet, dass seit dem Start etwas vorgefallen ist. Übersichtlicher ist es, das Skript gleich einzelne Metriken je Bit schreiben zu lassen.
Dazu kommt der Takt des Skripts: Es läuft minütlich, und get_throttled liefert nur den Zustand in diesem Moment. Eine Drosselung von wenigen Sekunden zwischen zwei Läufen zeigen die unteren Bits nicht, die Bits ab 16 dagegen schon. Gerade für kurze Unterspannungen ist der festgehaltene Teil deshalb der zuverlässigere.
Erreicht Prometheus im Container das Ziel 127.0.0.1:9100?
Nur mit network_mode: host. In einem gewöhnlichen Docker-Netz ist 127.0.0.1 der Container selbst, während der node_exporter außerhalb davon direkt auf dem Host läuft; das Ziel bleibt dann dauerhaft down. Für Grafana gilt dasselbe: Teilen sich beide Container ein Docker-Netz, steht in der Adresse der Datenquelle der Name des Prometheus-Dienstes statt 127.0.0.1.
Homelab auf dem Raspberry Pi
- Raspberry Pi 4 und 5: Vom SSD-Laufwerk booten über den Bootloader
- Unterbrechungsfreie Stromversorgung (USV) für Raspberry Pi 4 und 5: Die Top 5 Lösungen für anspruchsvolle Setups
- Lokales CI/CD für den Raspberry Pi: Automatisierung von Docker-Compose-Deployments
- Autonomer Docker-Compose-Heimserver mit Traefik, SSL und Watchtower
- Verzögerungsfreier lokaler Medienserver: Jellyfin auf Raspberry Pi 5 mit Hardware-Beschleunigung
- Raspberry Pi als gehärtetes WireGuard-VPN-Gateway mit Split-Tunneling
- Bare-Metal Performance Diagnostics: Prometheus & Grafana Dashboard für Raspberry Pi