Die vorige Massnahme (log_time statt ts) war NICHT ausreichend. Ursache ist tiefer: Telegraf schreibt pro Sammelzyklus EINEN Zeitstempel fuer den ganzen Batch, und Remote Write kann nur Millisekunden. Zwei Requests derselben Serie in derselben Millisekunde -> Prometheus lehnt den ganzen Batch ab -> FIFO-Kopf sitzt fest -> Node liefert gar nichts mehr (derselbe eingefrorene Timestamp alle ~15s im Log). Ein Zeitstempel-Trick kann das nicht loesen. Aggregation schon: basicstats fasst alle Metriken einer Serie pro 60s zu einem Punkt zusammen. Gemessen an 2000 echten x22-Zeilen: 2000 Punkte -> 4 Punkte, 0 Kollisionen, Requests vollstaendig gezaehlt (1997). VERSION 1.2.0, damit der Auto-Updater den Fix ausrollt.
27 KiB
netbird-telegraf-installer
Ein Befehl, und eine Node liefert Metriken + Logs an die zentrale Observability auf dem imac.
Der Ausgang läuft über den NetBird-Reverse-Proxy (imac-prometheus.x05.idx.wf, imac-loki.x05.idx.wf)
mit Bearer-Token — dadurch funktioniert der Installer auch auf Maschinen, die kein NetBird-Peer sind
(Büro-LAN, Kundenlaptop, CGNAT, VM ohne Client).
Diagnose: „Logs kommen nicht an"
Ein Befehl zeigt, warum:
curl -fsSL https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/install.sh \
| sh -s -- --diagnose
Er prüft genau die Stellen, die schon still versagt haben (kein E! in keinem Log):
| Prüfung | Warum |
|---|---|
| Dienst-Benutzer + Gruppen | Telegraf läuft als telegraf, nicht als root |
Jede Datei aus der files-Liste |
Existenz, Größe, Lesbarkeit aus Sicht des Dienst-Benutzers |
| Parser-Lauf ohne Filter | echte E!-Zeilen sichtbar machen |
| Offset-Zustand | erklärt, warum eine bestehende Datei „leer" wirkt |
Beispielausgabe:
-- Logpfade aus der aktiven Conf --
OK /var/log/apache2/keyhelp/access.log (75 Bytes)
NICHT LESBAR /home/users/u1/logs/d1/access.log (Benutzer telegraf) ← URSACHE
-> 3 Pfade, 2 lesbar, 0 leer, 1 nicht lesbar
Wichtig: initial_read_offset = "saved-or-end" heißt, dass beim ersten Lauf nur Neues gelesen wird. Bestehende Zeilen kommen erst mit neuen Zugriffen — für einen sofortigen Test eine Seite aufrufen und ein Intervall abwarten.
Der Konfig-Test prüft ALLE Dateien
Ein Detail, das schon eine Node lahmgelegt hat: Nie mit --input-filter prüfen.
# FALSCH — validiert nur die gefilterten Plugins:
telegraf --config … --config-directory … --test --input-filter cpu:mem
# RICHTIG — parst alle Dateien, genau wie der Dienststart:
telegraf --config … --config-directory … --test --test-wait 1
Mit --input-filter cpu:mem überspringt Telegraf alle übrigen Konfigdateien. Ein ungültiges Feld in telegraf.d/apache.conf lief damit durch, der Installer meldete „OK — Node liefert", und erst der Dienststart scheiterte danach mit:
Job for telegraf.service failed because the control process exited with error code.
Der Installer prüft deshalb ohne Filter und wertet nur echte Parser-Fehler (E! … loading config file) als Abbruch — nicht jede Warnung, denn ein fehlendes Input-Binary (nvidia-smi) zeigt sich erst beim Start, nicht beim Parsen.
Apache-Logs
Mit --role apache (oder automatisch, wenn apache2ctl/httpd gefunden wird) bindet der Installer Apache ein — auf zwei Wegen aus derselben Datei:
| Ziel | Was | Wofür |
|---|---|---|
| Loki | jede Zeile roh | Fehlersuche im Einzelfall |
| Prometheus | apache_access mit Tags resp_code, verb |
Request-Rate, Status-Klassen, Error-Rate — Panels und Alerts |
Logpfade werden automatisch gesammelt
Der Installer sammelt alle passenden Muster — nicht nur das erste. Auf einem KeyHelp-Host laufen zwei Strukturen parallel, und die globale Standarddatei ist leer:
| Panel | Pfadmuster |
|---|---|
| KeyHelp | /home/users/<user>/logs/<domain>/access.log (zweistufig, pro Domain) |
| KeyHelp | /var/log/apache2/<vhost>/access.log (z. B. keyhelp/access.log) |
| Plesk | /var/www/vhosts/<domain>/logs/access_log |
| cPanel | /usr/local/apache/domlogs/<domain> |
| Klassisch | /var/log/apache2/access.log, /var/log/httpd/access_log |
Verifiziert auf x22: Die Requests liegen unter /home/users/classi/logs/classi.parts/access.log und /var/log/apache2/keyhelp/access.log, während /var/log/apache2/access.log 0 Bytes hat. Ein Input auf die leere Datei hätte still nichts geliefert — leere Standarddateien werden per -s-Test ausgeschlossen.
Alle gefundenen Pfade landen als TOML-Liste in der Conf:
files = ["/var/log/apache2/*/access.log", "/home/users/*/logs/*/access.log"]
Jede Serie trägt ein path-Tag, damit man in Grafana nach Datei filtert. Überschreiben mit --apache-log <pfad> (mehrere Pfade leerzeichengetrennt).
Zusätzlich wird die CustomLog-Direktive aus /etc/apache2 bzw. /etc/httpd ausgewertet — die verlässlichste Quelle, ${APACHE_LOG_DIR} wird aufgelöst.
Zeitstempel-Kollisionen: der stille Totalausfall
Symptom. Ein Node liefert gar nichts mehr — nicht nur die Apache-Metriken,
sondern auch system_uptime, CPU, Disk. Andere Nodes laufen normal.
Erkennungsmerkmal. Im Prometheus-Log wiederholt sich derselbe eingefrorene Timestamp alle ~15 s:
duplicate sample for timestamp 1789343466232; overrides not allowed:
existing 43930, new value 51608
series="{__name__=\"apache_access_resp_bytes\", path=\"…/pixtasia.de/access.log\",
resp_code=\"200\", verb=\"GET\"}"
Derselbe Wert über Minuten heißt: ein vergifteter Batch sitzt im FIFO-Kopf und wird endlos wiederholt — nicht ein neuer Fehler pro Intervall.
Ursache. Telegraf schreibt pro Sammelzyklus einen Batch, dessen Metriken alle
denselben Zeitstempel tragen. Remote Write kennt nur Millisekunden. Treffen
zwei Requests derselben Serie (path + resp_code + verb) in dieselbe
Millisekunde, lehnt Prometheus den ganzen Batch ab. Telegrafs Puffer ist
FIFO: der Batch bleibt am Kopf stehen und blockiert jede weitere Serie — deshalb
fehlt am Ende die ganze Node.
Lösung: Aggregation statt Zeitstempel-Trick. Ein Zeitstempel-Trick kann das nicht beheben — feiner als Millisekunden geht Remote Write nicht. Ein Aggregator fasst alle Metriken einer Serie pro Intervall zu einem Punkt zusammen; damit ist eine Kollision strukturell unmöglich, unabhängig von der Last:
[[aggregators.basicstats]]
namepass = ["apache_access"]
period = "60s"
drop_original = true # zwingend — sonst sind die Einzelwerte zurück
stats = ["count", "sum", "mean"]
Gemessen an 2000 echten x22-Zeilen:
| Punkte | Kollisionen | |
|---|---|---|
| ohne Aggregator | 2000 | Risiko pro Zelle |
| mit Aggregator | 4 | 0 |
Die Requests werden dabei vollständig gezählt (1997 von 2000 — Differenz durch das Zeitfenster).
Entstehende Metriken (Telegraf stellt den Feldnamen voran):
| Metrik | Bedeutung |
|---|---|
apache_access_resp_bytes_count |
Requests je Gruppe — das brauchen die Panels |
apache_access_resp_bytes_sum |
übertragene Bytes je Gruppe |
apache_access_resp_bytes_mean |
mittlere Antwortgröße |
resp_code und verb bleiben Tags und damit Gruppenschlüssel — dafür sorgt
processors.converter oben im File (das eingebaute Muster liefert sie als Tags,
ein eigenes Muster als Felder; ohne den Converter brächen Filter nach resp_code).
Diagnose.
# derselbe Timestamp mehrfach = vergifteter Batch
docker logs observability-prometheus 2>&1 \
| grep "duplicate sample" | grep -oE "timestamp [0-9]+" | sort | uniq -c | tail
Leserechte: der stille Killer
Auf x22 waren 64 von 84 Logpfaden für telegraf unlesbar — inputs.tail meldet das nicht, es liefert einfach nichts, und der Node sieht „aktiv" aus. Zwei verschiedene Rechte-Welten:
| Ort | Rechte | Was hilft |
|---|---|---|
/var/log/apache2/… |
root:adm 0640 |
usermod -aG adm telegraf |
/home/users/<user>/logs/… |
<user>:<user> 0640 |
adm hilft nicht — ACL nötig |
Der Installer setzt dafür ACLs (setfacl -R -m u:telegraf:rX plus eine Default-ACL, damit neue Domain-Ordner das Recht erben). Das acl-Paket wird bei Bedarf nachinstalliert. Der Dienst bleibt im eingeschränkten Konto — kein root nötig.
Danach folgt ein Gegentest: Der Installer liest eine echte Logdatei als Dienst-Benutzer. Meldet er
[netbird-telegraf] Gegentest: 'telegraf' kann Apache-Logs lesen (…)
ist die Kette nachweislich in Ordnung.
Glob-Muster statt Einzelpfade
Die Conf enthält Muster, nicht die expandierten Dateinamen:
files = ["/var/log/apache2/*/access.log", "/home/users/*/logs/*/access.log"]
Damit wird eine neu angelegte Domain sofort erfasst, ohne dass der Installer erneut laufen muss. (Der Installer schaltet beim Rendern set -f ein — sonst würde die Shell die Muster selbst auflösen und feste Pfade in die Conf schreiben.)
/etc/default/telegraf wird gesourct — Werte müssen gequotet sein
Diese Datei wird mit . /etc/default/telegraf eingelesen (vom Installer und von der Telegraf-Unit). Ein ungequoteter Wert mit Leerzeichen bricht das Sourcing ab — bei mehreren Logpfaden versucht die Shell, den zweiten Pfad als Befehl auszuführen:
sh: /etc/default/telegraf: /home/users/classi/logs/classi.parts/access.log: Permission denied
Der Installer schreibt APACHE_LOG='…' deshalb mit einfachen Anführungszeichen. Zusätzlich liest er die Datei über load_defaults ein, das syntaktisch kaputte Dateien sichert und überschreibt statt abzubrechen — eine Node lässt sich so auch dann reparieren, wenn ihre Defaults-Datei bereits defekt ist.
Zwei Fallstricke
1. from_beginning existiert bei inputs.tail nicht. Ein solcher Block lässt den Dienst beim Start hart scheitern — systemctl start schlägt fehl und alle Metriken fallen aus, nicht nur die Apache-Logs:
E! loading config file /etc/telegraf/telegraf.d/apache.conf failed:
plugin inputs.tail: line 2: configuration specified the fields ["from_beginning"],
but they were not used ... does not exist in this version
Richtig ist initial_read_offset = "saved-or-end" (Default) — damit wird beim ersten Lauf nicht die komplette Historie ausgeschüttet. Für einen Test gegen eine vorgefüllte Datei "beginning" setzen.
2. Die Grok-Muster heißen COMMON_LOG_FORMAT und COMBINED_LOG_FORMAT — nicht HTTPD_COMMON_LOG/HTTPD_COMBINED_LOG_FORMAT. Die HTTPD_*-Namen aus anderen Grok-Sammlungen kennt Telegraf nicht:
E! [inputs.tail] Creating parser: no pattern found for %{HTTPD_COMBINED_LOG_FORMAT}
Die Reihenfolge in grok_patterns ist spezifisch → allgemein, damit die VHost-Varianten (example.com:80 ...) vor der einfachen Form greifen.
Response-Time
Common und Combined Log Format enthalten keine Antwortzeit. Für resp_time in den Metriken muss das LogFormat in Apache erweitert werden:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%D\" \"%{User-agent}i\"" combined_time
CustomLog ${APACHE_LOG_DIR}/access.log combined_time
%D = Dauer in Mikrosekunden. Danach im Grok-Muster als Feld ergänzen. Ohne diese Änderung sind alle anderen Werte trotzdem verfügbar — nur die Antwortzeit fehlt.
Auto-Updater und Force-Updater
Der Installer hält sich auf den Nodes selbst aktuell.
Prüfen
sh install.sh --version # installierte + verfügbare Version
sh install.sh --check # Exit 0 = aktuell, Exit 10 = Update verfügbar
Beides braucht keinen Token und kein root — gut für Monitoring-Checks.
Auto-Updater (systemd-Timer)
sh install.sh --name <node> --token <T> --install-update-timer daily
sh install.sh --name <node> --token <T> --install-update-timer 30min
sh install.sh --name <node> --token <T> --install-update-timer weekly
Legt telegraf-installer-update.timer an (Default daily 04:30, ±15 min Streuung).
Der Lauf ist billig: Es werden nur VERSION und der SHA des Installers verglichen.
Erst bei Abweichung lädt er den Installer und ruft sich mit --update-only auf.
Log: /var/log/telegraf-installer-update.log.
--update-only fasst nur telegraf.d/-Konfs und Hilfsscripts an: kein
Paket-Update, /etc/default/telegraf (und damit der Token) bleibt unberührt,
kein Neustart wenn sich nichts geändert hat.
Warum Version und Hash: Die VERSION erkennt neue Auslieferungen, der SHA
auch Korrekturen ohne Versionssprung (z. B. ein Fix an journal-tail.sh).
Ohne den Hash bliebe eine Node mit fehlerhaftem Script stehen.
Force-Updater
sh install.sh --force-update --name <node> --token <T>
Schreibt Konfs und Scripts immer neu, sichert sie vorher nach
/var/backups/telegraf-<zeitstempel>/ und startet den Dienst neu. Schlägt der
Konfig-Test fehl, wird automatisch zurückgerollt. Idempotent — mehrfaches
Ausführen ist folgenlos. Das Werkzeug nach einem kaputten Update oder wenn
jemand Dateien von Hand verändert hat.
Entfernen: sh install.sh --remove-update-timer
Windows
.\install.ps1 -Name <node> -Token <T> -Check # Versionsvergleich
.\install.ps1 -Name <node> -Token <T> -InstallUpdateTask # taeglich
.\install.ps1 -Name <node> -Token <T> -InstallUpdateTask -UpdateInterval hourly
.\install.ps1 -Name <node> -Token <T> -ForceUpdate
.\install.ps1 -RemoveUpdateTask
Die Aufgabe \NetBirdTelegraf\Update läuft mit denselben Semantiken
(Version + Hash, nur bei Änderung). Log:
%ProgramData%\netbird-telegraf\update.log.
Marker auf der Node
| Datei | Inhalt |
|---|---|
/etc/telegraf/CONFIG_VERSION |
zuletzt installierte Repo-Version |
/etc/telegraf/INSTALLER_SHA |
SHA256 des Installers zum Installationszeitpunkt |
/etc/telegraf/REPO_RAW |
genutzte Repo-Quelle (GitHub-Mirror, Testserver) |
REPO_RAW ist per Umgebungsvariable überschreibbar — nützlich für Tests,
Mirrors oder einen eigenen Fork.
Docker-Nodes (kein journalctl im Image)
Läuft Telegraf als Container (offizielles telegraf-Image), ist der Journal-Weg nicht möglich: das Image ist Debian ohne systemd und hat kein journalctl; /hostfs ist zudem read-only. Dafür gibt es scripts/syslog-tail.sh — es liest die Syslog-Dateien des Hosts unter /hostfs/var/log/.
Drei Fallstricke, die alle still scheitern (kein E!, das Panel bleibt einfach leer):
--config-directorymuss im Command stehen. Der Standard-CMD im Image ist nurtelegrafund liest ausschließlich/etc/telegraf/telegraf.conf. Alles intelegraf.d/wird ohne diesen Schalter ignoriert. Indocker-compose.yml:command: --config /etc/telegraf/telegraf.conf --config-directory /etc/telegraf/telegraf.d- Gruppe
admergänzen (group_add: ["4"]). Der Entrypoint des Images setzt Telegraf persetprivauf uid 999 — unabhängig vonuser:im Compose./var/log/sysloggehört Gruppeadm(Modus 640), als uid 999 also nicht lesbar. Ohneadmgibt das Script nichts aus. - State-Verzeichnis muss schreibbar sein (
SYSLOG_STATE_DIR). Voreinstellung ist/tmp/telegraf-syslog. Zeigt es auf ein nicht schreibbares Verzeichnis (z. B./var/lib/...als uid 999), kann der Offset nie gespeichert werden — das Script landet bei jedem Lauf im Erstanlauf-Zweig und liefert dauerhaft nichts. Seit der aktuellen Version warnt es in dem Fall auf stderr.
Output-Filter mitziehen: outputs.loki filtert per namepass. Enthält der Block namepass = ["docker_log"], wird das journal-Measurement verworfen und die System-Logs kommen nie an — auch wenn der Input läuft. journal ergänzen; im Remote-Write-Output gehört es in namedrop (Logs haben in Prometheus nichts zu suchen).
Kein Zeitstempel im erzeugten Line Protocol. Die Syslog-Zeit ist lokal (+02:00), mawk (Standard im Image) kennt keine Zeitzonen-Offsets — selbst berechnete Werte lagen 2 h in der Zukunft und Loki wies jeden Push ab: has timestamp too new. Ohne Zeitstempel stempelt Telegraf beim Einsammeln.
System-Logs (PVE und Nicht-Docker-Hosts)
Bis Version dieses Abschnitts lieferten nur Docker-Container Logs nach Loki
(inputs.docker_log) — PVE-Knoten und alle Hosts ohne Docker also gar nichts.
Jetzt werden zusätzlich journald-Logs übertragen.
Wie: scripts/journal-tail.sh liest journalctl -o json inkrementell und
gibt Influx Line Protocol aus (inputs.exec). Der Cursor steckt in jeder
Journal-Zeile (__CURSOR) und wird in /var/lib/telegraf-journal/cursor
gespeichert — keine Duplikate, kein Verlust bei Neustart oder Rotation.
Warum nicht inputs.journal: Das Plugin existiert in den offiziellen
Telegraf-Builds nicht (Docker-Image und InfluxData-Debian-Paket 1.40
geprüft; es braucht einen Build mit systemd-Headern).
Warum nicht /var/log/syslog: Auf PVE (Debian ohne rsyslog) existiert die
Datei nicht. ls /var/log/ zeigt dort journal/, pve/, pveproxy/,
pve-firewall.log, ceph/, corosync/ — aber kein syslog.
Feintuning in /etc/default/telegraf:
| Variable | Default | Bedeutung |
|---|---|---|
JOURNAL_PRIORITY |
warning |
warning, err, info, debug |
JOURNAL_MAX_LINES |
500 |
Obergrenze pro Lauf (Flutschutz) |
JOURNAL_BUDGET |
15 |
Sekunden, die journalctl lesen darf |
JOURNAL_SINCE |
— | nur beim ersten Lauf, z. B. -1h |
Standardmäßig werden Warnungen und schlimmer übertragen. Für Debugging
JOURNAL_PRIORITY=info setzen und Telegraf neu starten.
Labels in Loki: unit (z. B. pvedaemon.service), ident, priority,
jhost (Journal-Hostname), dazu host/node von Telegraf. Das jhost-Label
heißt bewusst nicht host — dieser Name gehört Telegrafs global_tag, sonst
filtert das Dashboard nach dem falschen Knoten.
Der Token — zuerst lesen
Jeder Aufruf braucht --token <TOKEN>. Ohne Token bricht das Script mit
FEHLER: Kein Token: --token <Bearer-Token> angeben ab.
Den Token legt man im NetBird-Dashboard an: https://x05.idx.wf → Reverse Proxy →
Service imac-prometheus → Authentication → Header → Preset „Bearer Token".
Für imac-loki denselben Wert eintragen (oder einen zweiten, dann aber getrennt halten).
Token nie in dieses Repo schreiben — er landet ausschließlich in /etc/default/telegraf (Modus 0600) auf der Zielmaschine.
Linux — Debian, Ubuntu, Proxmox VE, RHEL/Rocky/Alma/Fedora, Alpine, sonstige
curl -fsSL https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/install.sh \
| sudo sh -s -- --name <node-name> --token <BEARER-TOKEN>
| Option | Bedeutung |
|---|---|
--name <n> |
Node-Name im Dashboard (Default: hostname -s) |
--token <t> |
Pflicht. Bearer-Token des Reverse-Proxys |
--collector <ip> |
Direktweg innerhalb des NetBird statt Reverse Proxy (z. B. 100.83.134.46); braucht dann keinen Token-Zwang, aber die Node muss Peer sein |
--role proxmox|apache|docker|none |
Zusatz-Profil; Default auto erkennt Proxmox, Docker und Apache selbst |
--apache-log <pfad> |
Access-Log (Default /var/log/apache2/access.log) |
--uninstall |
alles entfernen |
Root-Rechte: Das Script braucht sie (Dienst, /etc/telegraf). Wo du schon root bist — PVE-Knoten, Hetzner-/Root-Server wie x17, LXC-Container, minimale Debian-Installationen — kein sudo: dort ist es oft gar nicht installiert und der erste Befehl bricht mit sudo: command not found ab. Auf normalen Desktops/Servern mit eigenem Benutzer (Ubuntu-Desktop, ROG): | sudo sh -s -- ….
Prüfen statt raten: id -u — kommt 0, ohne sudo. Das Script prüft es selbst und bricht mit klarer Meldung ab, wenn es nicht root ist.
Ablauf: Paketquelle von InfluxData (apt/dnf/apk) oder statisches Binary (amd64/arm64/armv7) → /etc/telegraf/telegraf.conf + telegraf.d/ aus diesem Repo → /etc/default/telegraf mit NODE_NAME, PROM_URL, LOKI_URL, TELEGRAF_TOKEN → systemd-Dienst telegraf, enabled, Konfig-Test vor dem Start.
Direktweg (Node ist NetBird-Peer)
curl -fsSL …/install.sh | sudo sh -s -- --name <node> --token <TOKEN> --collector 100.83.134.46
Proxmox VE
Kein API-Token nötig. Der Installer nutzt pvesh direkt (Telegraf läuft für diese Rolle
als root — das Drop-in 10-proxmox-root.conf setzt das). Damit entfällt die gesamte
Token-/ACL-Thematik.
Warum nicht
inputs.proxmox? Das Plugin fragt als Erstes/nodes/<node>/dnsab und braucht dortSys.Audit. Schlägt das fehl, liefert es komplett nichts — ohne Logmeldung. Mehrere ACL-Versuche (PVEAuditorauf/, auf/nodes, auf/nodes/<node>, eigene Rolle mitSys.Audit) blieben auf PVE 8 mit403erfolglos.
Dann auf jedem PVE-Knoten (auf dem Host selbst, nicht in einer VM).
Auf PVE (und auf Root-Servern wie x17) gibt es kein sudo — du bist dort bereits root, also ohne sudo:
curl -fsSL https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/install.sh \
| sh -s -- --name <PVE-KNOTENNAME> --token <BEARER-TOKEN> --role proxmox
Auf Debian/Ubuntu/Normalnutzer dagegen
| sudo sh -s -- …verwenden. Das Script prüftid -uselbst und bricht mit klarer Meldung ab, wenn es nicht root ist.
Der Installer erkennt den PVE-Knoten selbst (pvesh get /nodes) und legt das systemd-Drop-in
10-proxmox-root.conf an — Telegraf läuft für diese Rolle als root, weil pvesh root verlangt.
Liefert pro Gast: proxmox_vm_cpu_usage_percent, _cpu_cores, _mem_bytes, _mem_max_bytes,
_mem_usage_percent, _swap_bytes, _disk_bytes, _disk_max_bytes, _diskread/_diskwrite_bytes_total,
_net_in/_net_out_bytes_total, _uptime_seconds, _running — je mit vmid, name, node, type, status.
Plus die normalen Host-Metriken des Knotens.
Wenn nach der Installation keine VM-Metriken kommen:
systemctl cat telegraf | grep UsermussUser=rootzeigen. Vorher prüfen:pvesh get /cluster/resources --output-format jsonmuss als root Daten liefern. Als Nicht-root gibtpveshnuripcc_send_rec[...] failedaus — ohne Fehler im Log.
Apache
Wird automatisch erkannt (apache2ctl/httpd). Access-Log geht roh nach Loki. Für Request-Metriken inputs.apache in telegraf/apache.conf einschalten (braucht mod_status).
Windows — PowerShell als Administrator
Set-ExecutionPolicy Bypass -Scope Process -Force
& ([scriptblock]::Create((iwr -useb https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/install.ps1))) -Name ROG -Token <BEARER-TOKEN>
Installiert nach C:\Program Files\Telegraf, Dienst telegraf; liefert CPU/RAM/Disk/Net/Dienste + Eventlog (Warnung/Fehler). -Uninstall entfernt alles.
GPU-Metriken
| Hersteller | Erkennung | Metriken |
|---|---|---|
| NVIDIA | nvidia-smi -L funktioniert |
Auslastung, VRAM, Temperatur, Leistung, Takte, P-State |
| AMD | rocm-smi vorhanden |
Auslastung, Temperatur, Leistung, VRAM (via scripts/gpu-rocm.sh) |
| Intel | /dev/dri/renderD128 |
Hinweis im Log — intel_gpu_top wird nicht automatisch erfasst |
AMD liefert sieben Metriken (Auslastung, VRAM genutzt/gesamt, Temperatur edge/junction/memory, Leistung). NVIDIA entsprechend über inputs.nvidia_smi.
Im Dashboard: Row GPU (Auslastung, Speicher, Temperatur, Leistung). Leere Panels heißen: keine GPU-Node im Mesh.
Beim Aktualisieren des AMD-Scripts (falls rocm-smi seine Spalten ändert) beide Dateien neu holen — Script und Conf, und data_format muss prometheus bleiben:
sudo curl -fsSL …/scripts/gpu-rocm.sh | sudo tee /etc/telegraf/gpu-rocm.sh >/dev/null
sudo chmod +x /etc/telegraf/gpu-rocm.sh
sudo sh -c 'cat > /etc/telegraf/telegraf.d/gpu.conf <<EOF
[[inputs.exec]]
interval = "30s"
timeout = "20s"
data_format = "prometheus"
commands = ["/etc/telegraf/gpu-rocm.sh"]
EOF'
sudo systemctl restart telegraf
Im Docker-Betrieb muss der Treiber im Container verfügbar sein (nvidia-container-toolkit bzw. --device /dev/dri); als systemd-Dienst ist das automatisch der Fall.
Prüfen
TOKEN=<BEARER-TOKEN>
curl -s -H "Authorization: Bearer $TOKEN" \
"https://imac-prometheus.x05.idx.wf/api/v1/query?query=system_uptime{node=\"<node-name>\"}"
journalctl -u telegraf -f
Im Grafana-Dashboard „NetBird Observability — Overview“ erscheint die Node automatisch im Node-Filter.
Grafana selbst: http://100.83.134.46:3000 (nur im NetBird, Login admin).
Docker-Host ohne root
Wer kein sudo hat, aber in der Gruppe docker ist: Container-Variante aus
netbird-observability/stacks/telegraf-node (privates Repo).
Dort ist network_mode: host gesetzt — ohne das sieht Telegraf nur lo+eth0 statt der echten Interfaces.
Alte Logs archivieren (Historie nachträglich auswertbar machen)
inputs.tail liest mit initial_read_offset = "saved-or-end" nur Neues — die
vorhandene Historie bleibt unausgewertet. Dafür gibt es ein eigenes Skript, das
dieselben Zeilen parst und als Prometheus-Blöcke ablegt:
# Auf der Node: erst messen (ändert nichts)
curl -fsSL <raw>/scripts/x22-log-archive.sh -o /root/archiv.sh
bash /root/archiv.sh # Bestandsaufnahme
# dann archivieren
bash /root/archiv.sh --backfill # erzeugt apache-archive.openmetrics + tar.gz
Das Skript prüft seine eigene Ausgabe vor der Übergabe: Zeitraum, Einheit (Sekunden) und ein Zukunfts-Check — Punkte nach „jetzt" werden gemeldet, weil sie später beim Import die Zeitreferenz verschieben würden.
Eingespielt wird nur in die Archiv-Instanz, nie in die Produktions-TSDB:
scp /root/apache-archive/apache-archive.openmetrics mm@<imac>:/tmp/
ssh mm@<imac> 'sudo /usr/local/bin/prom-archive-import.sh --file /tmp/apache-archive.openmetrics'
Geparst werden Access- und Error-Logs, inklusive rotierter .log.1/.log.N.gz.
Was entsteht: apache_archive_requests_total (je Domain/Status/Methode/Stunde),
_response_bytes_total, _unique_clients, _errors_total (je Level),
_log_lines_total. Als Datasource in Grafana einhängen
(http://archive-prometheus:9090) — Live und Archiv sind dann getrennt abfragbar.
Archiv-Import: Schutzschichten
Alte Logs lassen sich als Prometheus-Blöcke archivieren (scripts/apache-log-archive.py).
Der Import in eine laufende TSDB ist heikel — drei Fehler sind möglich, alle
still:
| Fehler | Folge | Schutz |
|---|---|---|
| Zeitstempel in Millisekunden statt Sekunden | Blöcke im Jahr 58.662, Prometheus verwirft sie als „too far into the future" | Einheiten-Wächter im Skript (Abbruch ab Jahr 2100) |
| Block reicht in die Zukunft | Prometheus verschiebt seine Zeitreferenz, alle Live-Samples gelten als „too old" — alle Nodes fallen aus | Zukunft-Prüfung in prom-archive-import.sh (Abbruch, Toleranz 5 min) |
rm -rf <tsdb>/01M* beim Aufräumen |
Glob trifft alle Blöcke → gesamte Historie gelöscht | kein Glob; nur exakte Block-IDs; Pflicht-Snapshot vorher |
Deshalb: Archiv-Blöcke nie in die Produktions-TSDB, sondern in die getrennte
Instanz (stacks/archive-prometheus, Port 9091). Sie nimmt keine Live-Daten an
und kann die Produktion nicht beeinflussen.
Sicherheit
- Der Proxy verlangt Bearer-Token; das Header wird vor dem Weiterleiten entfernt und liegt damit nicht bei Prometheus/Loki.
- Telegraf läuft als Benutzer
telegraf(Docker-Socket read-only via Gruppedocker, Apache-Logs via Gruppeadm). - Ausnahme
--role proxmox: systemd-Drop-in setztUser=root, weilpveshroot benötigt. Nur auf PVE-Hosts, wo du ohnehin root bist. - Dieses Repo ist öffentlich und enthält keine Secrets.