No Prometheus metric exposes drive wear — endurance cannot be alerted on #549

Closed
opened 2026-08-21 20:38:19 +00:00 by claude-bot · 2 comments
Member

Split out of #434, whose follow-up asked for a device-wear alert rule alongside the Ceph health rules. The rule was never written because there is no metric to write it against.

What was checked

ceph-mgr prometheus module   http://rook-ceph-mgr.rook-ceph.svc:9283/metrics
  -> no ceph_device_* series
  -> DEVICE_HEALTH does not appear in ceph_health_detail

rook-ceph-exporter           http://rook-ceph-exporter.rook-ceph.svc:9926/metrics
  -> only ceph_blk_kernel_device_*_discard_op / _discard_threads
  -> no wear, no SMART

The data exists, just not in Prometheus:

$ ceph device ls
DEVICE                      HOST:DEV       DAEMONS  WEAR  LIFE EXPECTANCY
CT1000P3PSSD8_2326E6E8E67D  k8s-3:nvme0n1  osd.1     82%
CT1000P3PSSD8_2332E86B749A  k8s-1:nvme0n1  osd.2     87%
CT1000P3PSSD8_2332E86B74BC  k8s-2:nvme0n1  osd.0     81%

mgr/devicehealth/enable_monitoring is true, so SMART history is being collected to RADOS — ceph device get-health-metrics <devid> returns a full time series. It simply never reaches the TSDB.

Ceph's own DEVICE_HEALTH check is also unavailable: it fires on life expectancy, and the LIFE EXPECTANCY column is empty because no failure-prediction model is active.

Why it matters

This is the gap that let the OSD drives reach 81-87% before anyone noticed. They now have roughly 2.5-5 months left at the measured 152 GB/day (see #434). Replacements are planned, but the successor drives will need the same monitoring, and today nothing would warn about them either.

Note that drive wear is invisible in every other signal: ceph -s reads active+clean at 87% wear, and no health check fires until the device actually fails.

Options

  1. Small exporter or CronJob that runs ceph device ls (or reads the devicehealth RADOS pool) and exposes wear as a gauge. Most direct; new machinery to maintain.
  2. smartctl_exporter as a DaemonSet. Broader value — would also cover the Kingston boot drives, which are likewise unmonitored — but needs device access on Talos nodes, and the OSD NVMes are PCI-passed-through to the VMs so host-side and guest-side coverage differ.
  3. Enable Ceph failure prediction so LIFE EXPECTANCY populates and DEVICE_HEALTH can fire. Least new code, but the check still has to be exported to Prometheus, and prediction quality on consumer QLC is unproven.
  4. Accept manual tracking. Wear moves slowly (~1% per 5.8 days on the fastest drive), so a periodic manual check is not unreasonable — but it is what failed last time.

No recommendation locked in; option 2 has the widest coverage and option 1 the lowest cost.

Refs #434

Split out of #434, whose follow-up asked for a device-wear alert rule alongside the Ceph health rules. The rule was never written because **there is no metric to write it against.** ## What was checked ``` ceph-mgr prometheus module http://rook-ceph-mgr.rook-ceph.svc:9283/metrics -> no ceph_device_* series -> DEVICE_HEALTH does not appear in ceph_health_detail rook-ceph-exporter http://rook-ceph-exporter.rook-ceph.svc:9926/metrics -> only ceph_blk_kernel_device_*_discard_op / _discard_threads -> no wear, no SMART ``` The data exists, just not in Prometheus: ``` $ ceph device ls DEVICE HOST:DEV DAEMONS WEAR LIFE EXPECTANCY CT1000P3PSSD8_2326E6E8E67D k8s-3:nvme0n1 osd.1 82% CT1000P3PSSD8_2332E86B749A k8s-1:nvme0n1 osd.2 87% CT1000P3PSSD8_2332E86B74BC k8s-2:nvme0n1 osd.0 81% ``` `mgr/devicehealth/enable_monitoring` is `true`, so SMART history is being collected to RADOS — `ceph device get-health-metrics <devid>` returns a full time series. It simply never reaches the TSDB. Ceph's own `DEVICE_HEALTH` check is also unavailable: it fires on life expectancy, and the `LIFE EXPECTANCY` column is empty because no failure-prediction model is active. ## Why it matters This is the gap that let the OSD drives reach 81-87% before anyone noticed. They now have roughly 2.5-5 months left at the measured 152 GB/day (see #434). Replacements are planned, but the successor drives will need the same monitoring, and today nothing would warn about them either. Note that drive wear is invisible in every other signal: `ceph -s` reads `active+clean` at 87% wear, and no health check fires until the device actually fails. ## Options 1. **Small exporter or CronJob** that runs `ceph device ls` (or reads the devicehealth RADOS pool) and exposes wear as a gauge. Most direct; new machinery to maintain. 2. **smartctl_exporter as a DaemonSet.** Broader value — would also cover the Kingston boot drives, which are likewise unmonitored — but needs device access on Talos nodes, and the OSD NVMes are PCI-passed-through to the VMs so host-side and guest-side coverage differ. 3. **Enable Ceph failure prediction** so `LIFE EXPECTANCY` populates and `DEVICE_HEALTH` can fire. Least new code, but the check still has to be exported to Prometheus, and prediction quality on consumer QLC is unproven. 4. **Accept manual tracking.** Wear moves slowly (~1% per 5.8 days on the fastest drive), so a periodic manual check is not unreasonable — but it is what failed last time. No recommendation locked in; option 2 has the widest coverage and option 1 the lowest cost. Refs #434
Author
Member

Der Issue ist überholt, und zwar in eine Richtung, die die Priorität eher erhöht als senkt.

Die OSDs sind nicht mehr die Crucial P3. Der CephCluster benennt heute drei Samsung PM983 per by-id-Pfad, und ceph_disk_occupation bestätigt das live. Der im Issue als geplant beschriebene Austausch hat stattgefunden — die 81–87 % Verschleiß liegen nicht mehr im Ceph-Datenpfad.

Die verschlissenen Laufwerke sind aber nicht weg, sondern umgewidmet. Die Talos-Konfiguration weist die Crucial P3 als EPHEMERAL-Volume zu, dokumentiert in kubernetes/talos/patches/k8s-1.yaml. Pro Node also: Kingston OM8PGP41024Q als Systemdisk, Samsung PM983 als OSD, Crucial P3 als EPHEMERAL. Node-exporter sieht alle drei.

Damit kehrt sich die Bewertung der Optionen um:

  • Option 1 (Ceph-basierter Exporter) war die billigste und deckt jetzt genau die Laufwerke ab, die es am wenigsten brauchen — die neuen Enterprise-OSDs. Die verschlissenen Crucial kennt Ceph nicht mehr, sie tauchen in ceph device ls nicht auf. Die Option löst das Problem nicht mehr.
  • Option 2 (node-weiter SMART-Exporter) hatte als Einwand „the OSD NVMes are PCI-passed-through to the VMs". Der ist mit der Bare-Metal-Umstellung entfallen; alle drei Nodes sehen ihre Laufwerke direkt.

Option 2 ist also der einzige verbliebene Weg — und er kollidiert mit einer harten Hausregel. smartctl_exporter dokumentiert privileged: true und user: root, weil der Kernel die nötigen Kommandos für Nicht-root blockiert. Für NVMe braucht der Verschleißwert einen Admin-ioctl auf /dev/nvmeX, also mindestens CAP_SYS_ADMIN. Privilegierte Container sind hier ausgeschlossen. Ich baue darum keinen Workaround und lege das als Widerspruch vor statt als Vorschlag.

Was ohne neue Privilegien geht, ist schon gebaut: die Controller-Temperatur kommt über hwmon aus sysfs und liegt für alle neun Laufwerke vor. Sie ist im neuen Dashboard (#667) drin, zusammen mit einem Panel, das ausdrücklich benennt, was fehlt — damit ein grüner Bildschirm nicht als gesundes Laufwerk gelesen wird.

Ein Messwert, der schon jetzt etwas sagt: die Crucial schreiben mit 1–5 ms mittlerer Latenz, die Samsung-OSDs mit 50–76 µs. Das ist kein Verschleißwert, aber es ist der Unterschied zwischen einem verbrauchten Consumer-QLC und einem Enterprise-Laufwerk — und er trifft ausgerechnet den Container-State.

Zwei Wege, beide deine Entscheidung: entweder die Regel für genau diesen DaemonSet aufweichen (dann bitte explizit, nicht durch mich hintenherum), oder EPHEMERAL akzeptieren als „läuft bis es ausfällt" und stattdessen absichern, dass ein Node den Ausfall überlebt.

Der Issue ist überholt, und zwar in eine Richtung, die die Priorität eher erhöht als senkt. **Die OSDs sind nicht mehr die Crucial P3.** Der CephCluster benennt heute drei Samsung PM983 per by-id-Pfad, und `ceph_disk_occupation` bestätigt das live. Der im Issue als geplant beschriebene Austausch hat stattgefunden — die 81–87 % Verschleiß liegen nicht mehr im Ceph-Datenpfad. **Die verschlissenen Laufwerke sind aber nicht weg, sondern umgewidmet.** Die Talos-Konfiguration weist die Crucial P3 als `EPHEMERAL`-Volume zu, dokumentiert in `kubernetes/talos/patches/k8s-1.yaml`. Pro Node also: Kingston OM8PGP41024Q als Systemdisk, Samsung PM983 als OSD, Crucial P3 als EPHEMERAL. Node-exporter sieht alle drei. Damit **kehrt sich die Bewertung der Optionen um**: - **Option 1 (Ceph-basierter Exporter)** war die billigste und deckt jetzt genau die Laufwerke ab, die es am wenigsten brauchen — die neuen Enterprise-OSDs. Die verschlissenen Crucial kennt Ceph nicht mehr, sie tauchen in `ceph device ls` nicht auf. Die Option löst das Problem nicht mehr. - **Option 2 (node-weiter SMART-Exporter)** hatte als Einwand „the OSD NVMes are PCI-passed-through to the VMs". Der ist mit der Bare-Metal-Umstellung entfallen; alle drei Nodes sehen ihre Laufwerke direkt. Option 2 ist also der einzige verbliebene Weg — **und er kollidiert mit einer harten Hausregel.** `smartctl_exporter` dokumentiert `privileged: true` und `user: root`, weil der Kernel die nötigen Kommandos für Nicht-root blockiert. Für NVMe braucht der Verschleißwert einen Admin-ioctl auf `/dev/nvmeX`, also mindestens `CAP_SYS_ADMIN`. Privilegierte Container sind hier ausgeschlossen. Ich baue darum keinen Workaround und lege das als Widerspruch vor statt als Vorschlag. Was **ohne** neue Privilegien geht, ist schon gebaut: die Controller-Temperatur kommt über hwmon aus sysfs und liegt für alle neun Laufwerke vor. Sie ist im neuen Dashboard (#667) drin, zusammen mit einem Panel, das ausdrücklich benennt, was fehlt — damit ein grüner Bildschirm nicht als gesundes Laufwerk gelesen wird. Ein Messwert, der schon jetzt etwas sagt: die Crucial schreiben mit **1–5 ms** mittlerer Latenz, die Samsung-OSDs mit **50–76 µs**. Das ist kein Verschleißwert, aber es ist der Unterschied zwischen einem verbrauchten Consumer-QLC und einem Enterprise-Laufwerk — und er trifft ausgerechnet den Container-State. Zwei Wege, beide deine Entscheidung: entweder die Regel für genau diesen DaemonSet aufweichen (dann bitte explizit, nicht durch mich hintenherum), oder EPHEMERAL akzeptieren als „läuft bis es ausfällt" und stattdessen absichern, dass ein Node den Ausfall überlebt.
Author
Member

Abschluss, mit Messwerten — und einer Korrektur am Issue-Text selbst.

Der Issue beschrieb die Crucial P3 als OSDs. Das stimmt seit dem Laufwerkstausch nicht mehr: die OSDs sind Samsung PM983, die Crucial wurden nicht entsorgt, sondern tragen jetzt das EPHEMERAL-Volume. Wer diesen Issue später liest, sollte das wissen, bevor er die Zahlen darin einordnet.

Was ausgeliefert wurde: smartctl_exporter als DaemonSet, ServiceMonitor mit Node-Relabeling, sechs Alarmregeln, Panels im Disk-Health-Dashboard. Abdeckung: alle neun Laufwerke, nicht nur die drei OSDs.

Gemessener Zustand:

Rolle k8s-1 k8s-2 k8s-3
Crucial P3 (EPHEMERAL) 87 % 81 % 83 %
Kingston (System) 13 % 10 % 13 %
Samsung PM983 (OSD) 3 % 2 % 3 %

Dazu 18 Media-Errors auf der Crucial in k8s-1 — nicht behebbare Datenintegritätsfehler. NvmeDriveWearHigh steht für alle drei Crucial auf pending und geht nach der for: 1h auf firing.

Der Weg dahin, für die Nachwelt: drei Anläufe, weil ich den Blocker zweimal in der falschen Schicht gesucht habe. Capabilities (CAP_SYS_ADMIN + CAP_SYS_RAWIO) reichten nicht, Seccomp-Unconfined auch nicht. Beides war messbar wirksam — CapEff 0x220000, Seccomp 2 — und beides irrelevant. Entschieden hat ein kleinerer Test: head -c 512 /dev/nvme0n1 scheiterte ebenfalls mit EPERM. Ein simples Blockgerät-Lesen braucht keinen ioctl und keine Capability. Die Sperre war die Device-Cgroup, und Kubernetes bietet keine Geräte-Allowlist im Pod-Spec. privileged: true ist hier der einzige Mechanismus, nicht eine bequeme Abkürzung.

Zwei Punkte bleiben offen und sind bewusst nicht Teil dieses Issues:

  1. Die 18 Media-Errors alarmieren nicht. NvmeDriveMediaErrors prüft den Zuwachs über 6 h, nicht den Bestand — bewusst, damit ein Laufwerk mit alten Fehlern nicht dauerhaft alarmiert. In genau diesem Fall fällt die Regel durch.
  2. Überwacht ist nicht ersetzt. Drei Laufwerke über 80 % Verschleiß tragen den Container-State, und ein sterbendes NVMe hängt hier, statt Fehler zu liefern (nvme_core.io_timeout=4294967295). Was ein Node-Ausfall dieser Art bedeutet, ist eine eigene Frage.
Abschluss, mit Messwerten — und einer Korrektur am Issue-Text selbst. **Der Issue beschrieb die Crucial P3 als OSDs.** Das stimmt seit dem Laufwerkstausch nicht mehr: die OSDs sind Samsung PM983, die Crucial wurden nicht entsorgt, sondern tragen jetzt das EPHEMERAL-Volume. Wer diesen Issue später liest, sollte das wissen, bevor er die Zahlen darin einordnet. **Was ausgeliefert wurde:** smartctl_exporter als DaemonSet, ServiceMonitor mit Node-Relabeling, sechs Alarmregeln, Panels im Disk-Health-Dashboard. Abdeckung: alle neun Laufwerke, nicht nur die drei OSDs. **Gemessener Zustand:** | Rolle | k8s-1 | k8s-2 | k8s-3 | |---|---|---|---| | Crucial P3 (EPHEMERAL) | **87 %** | **81 %** | **83 %** | | Kingston (System) | 13 % | 10 % | 13 % | | Samsung PM983 (OSD) | 3 % | 2 % | 3 % | Dazu **18 Media-Errors** auf der Crucial in k8s-1 — nicht behebbare Datenintegritätsfehler. `NvmeDriveWearHigh` steht für alle drei Crucial auf pending und geht nach der `for: 1h` auf firing. **Der Weg dahin, für die Nachwelt:** drei Anläufe, weil ich den Blocker zweimal in der falschen Schicht gesucht habe. Capabilities (`CAP_SYS_ADMIN` + `CAP_SYS_RAWIO`) reichten nicht, Seccomp-Unconfined auch nicht. Beides war messbar wirksam — `CapEff 0x220000`, `Seccomp 2` — und beides irrelevant. Entschieden hat ein kleinerer Test: `head -c 512 /dev/nvme0n1` scheiterte ebenfalls mit EPERM. Ein simples Blockgerät-Lesen braucht keinen ioctl und keine Capability. Die Sperre war die **Device-Cgroup**, und Kubernetes bietet keine Geräte-Allowlist im Pod-Spec. `privileged: true` ist hier der einzige Mechanismus, nicht eine bequeme Abkürzung. **Zwei Punkte bleiben offen und sind bewusst nicht Teil dieses Issues:** 1. Die 18 Media-Errors alarmieren **nicht**. `NvmeDriveMediaErrors` prüft den Zuwachs über 6 h, nicht den Bestand — bewusst, damit ein Laufwerk mit alten Fehlern nicht dauerhaft alarmiert. In genau diesem Fall fällt die Regel durch. 2. Überwacht ist nicht ersetzt. Drei Laufwerke über 80 % Verschleiß tragen den Container-State, und ein sterbendes NVMe hängt hier, statt Fehler zu liefern (`nvme_core.io_timeout=4294967295`). Was ein Node-Ausfall dieser Art bedeutet, ist eine eigene Frage.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: konairius/homelab#549