Contexte : l’exporter SMART des Raspberry Pi ne lisait aucun disque jusqu’à la relecture des tableaux Grafana, et le dernier disque dur du cluster a été remplacé par un SSD fin septembre. Les deux changements étaient de bonnes nouvelles. Ensemble, ils ont produit une alerte par nuit.
Le symptôme : 52 °C à deux heures du matin
L’alerte s’appelle DiskTempHighHDD. Elle dit qu’un disque dépasse 50 °C depuis 15 minutes. Elle sonne la nuit, presque toutes les nuits, et toujours sur le même nœud : un worker Raspberry Pi dont le disque système est un SanDisk SSD PLUS branché en USB.
Chaque alerte déclenche, en plus, le script d’investigation automatique qui collecte le contexte et rédige un rapport. Le rapport est donc devenu, lui aussi, quotidien. Et il disait chaque fois la même chose : rien ne se passe sur ce nœud.
Les chiffres, sur l’historique de la base de métriques :
| Observation | |
|---|---|
| Température au pic | 52 à 53 °C |
| Durée du pic | environ 20 minutes |
| E/S de l’hôte pendant le pic | aucune |
| Tâche planifiée à cette heure | aucune |
| Heure du pic le 11 octobre | 02:15 UTC |
| Heure du pic le 25 octobre | 01:45 UTC |
Un disque qui chauffe sans travailler, c’est déjà curieux. Un disque qui chauffe sans travailler à une heure qui recule, c’est un indice.
L’investigation : une heure qui dérive
La première hypothèse naïve, c’est une tâche planifiée : un fstrim hebdomadaire, une sauvegarde, une compaction. Elle ne tient pas. Une tâche cron ou un timer systemd tombe à heure fixe sur l’horloge murale, et ici l’heure recule de 30 minutes en 14 jours, soit environ 2 minutes par jour. Rien sur l’hôte ne tourne sur une période de 23 h 58.
La deuxième hypothèse, c’est la charge. Elle ne tient pas non plus : les métriques d’E/S du nœud sont plates pendant les 20 minutes du pic. Le disque chauffe sans que le système lui demande quoi que ce soit.
Reste ce qui se passe dans le disque. Un SSD a sa propre vie : collecte des blocs libérés, nivellement de l’usure, vérification en arrière-plan des cellules. Ces opérations sont déclenchées par le firmware, sur sa propre horloge, qui ne connaît ni NTP ni le fuseau horaire. Une périodicité interne qui n’est pas exactement de 24 heures produit exactement ce qu’on observe : un pic régulier, de durée constante, qui glisse doucement sur l’horloge murale.
Je n’ai pas de documentation du constructeur pour le confirmer. C’est le seul candidat qui colle aux trois observations : pas d’E/S, durée stable, dérive régulière. Et surtout, ce n’est pas un problème : 53 °C reste loin des 70 °C pour lesquels ce SSD est donné en fonctionnement.
Le problème n’était pas le disque. C’était la règle.
La cause : une règle écrite pour des disques à plateaux
Voici l’expression telle qu’elle était :
smartctl_device_temperature{temperature_type="current", device=~"sd.*"} > 50
Le sélecteur device=~"sd.*" voulait dire « disque SATA », et à l’époque où la règle a été écrite, un disque SATA dans ce cluster, c’était un disque dur. Les seuils suivent cette logique : 50 °C en warning, 58 °C en critical, des valeurs raisonnables pour un HDD, dont la mécanique vieillit mal au chaud.
Deux choses ont changé depuis, sans que personne ne relise la règle :
- Le dernier disque dur du cluster est parti le 26 septembre, remplacé par un SSD. Tous les
sd*des Pi sont désormais des SSD branchés en USB. - L’exporter SMART a recommencé à lire les disques après la correction de son image. Les cinq SSD des Pi ont commencé à remonter leur température.
La règle est restée la même. Ce qu’elle surveillait, non. Un seuil de 50 °C appliqué à un SSD qui fait son ménage nocturne à 52 °C, c’est une alerte par nuit, garantie.
Le critère : la vitesse de rotation
La tentation, à ce stade, c’est d’exclure le nœud concerné par son nom, ou de remonter le seuil à 55 °C. Les deux reviennent à cacher le symptôme. Le nom d’un nœud ne dit rien du disque qu’il porte, et un seuil unique ne peut pas être juste à la fois pour un HDD et pour un SSD.
Il faut un critère qui décrive le matériel lui-même. smartctl en fournit un : la vitesse de rotation. Un disque à plateaux annonce ses tours par minute ; un SSD n’en a pas. Dans ce homelab, l’exporter n’expose la série smartctl_device_rotation_rate que pour les deux WD Red du NAS (5400 tr/min). Les SSD des Pi ne l’ont pas du tout.
Écrire le filtre en > 0 plutôt que de compter sur l’absence de la série couvre les deux comportements possibles d’un exporter : une série absente, ou une série à zéro pour un SSD. Dans les deux cas, le disque est classé SSD.
sd* > 50 °C pendant 15 minsd* > 50 °C for 15 min
Écrite pour des disques à plateaux. Le sélecteur sd.* attrape aussi les SSD USB.Written for spinning disks. The sd.* selector also catches USB SSDs.
52-53 °C, ~20 min, sans E/S52-53 °C, ~20 min, no I/O
Un cycle interne du firmware du SSD. L'alerte sonne, une investigation automatique part.An internal firmware cycle of the SSD. The alert fires, an automatic investigation starts.
rotation_rate > 0rotation_rate > 0
Seuls les disques à plateaux exposent une vitesse de rotation : 2 HDD d'un côté, 5 SSD de l'autre.Only spinning disks expose a rotation rate: 2 HDDs on one side, 5 SSDs on the other.
HDD 50/58 °C · SSD 60/68 °CHDD 50/58 °C · SSD 60/68 °C
and on(…) pour les HDD, unless on(…) pour les SSD : exclusives. Le pic nocturne reste sous le seuil.and on(…) for HDDs, unless on(…) for SSDs: mutually exclusive. The nightly peak stays below the threshold.
Les règles HDD gardent leurs seuils, mais seulement pour les disques qui tournent :
- alert: DiskTempHighHDD
expr: |
smartctl_device_temperature{temperature_type="current", device=~"sd.*"} > 50
and on(instance, device) smartctl_device_rotation_rate > 0
for: 15m
labels: { severity: warning }
Et deux nouvelles règles prennent les SSD en charge, avec des seuils pensés pour eux :
- alert: DiskTempHighSSD
expr: |
smartctl_device_temperature{temperature_type="current", device=~"sd.*"} > 60
unless on(instance, device) smartctl_device_rotation_rate > 0
for: 15m
labels: { severity: warning }
- alert: DiskTempCriticalSSD
expr: |
smartctl_device_temperature{temperature_type="current", device=~"sd.*"} > 68
unless on(instance, device) smartctl_device_rotation_rate > 0
for: 5m
labels: { severity: critical }
and on(instance, device) garde les séries qui ont une vitesse de rotation ; unless on(instance, device) garde celles qui n’en ont pas. C’est la même paire d’opérateurs que celle qui avait rendu exclusives deux règles de restart dans 48 alertes pour 24 pods, et pour la même raison : un disque tombe dans exactement une famille, jamais dans deux, jamais dans aucune.
Les seuils SSD partent de la limite de fonctionnement : 60 °C laisse 10 °C de marge avant les 70 °C du constructeur et 7 °C au-dessus du pic nocturne observé ; 68 °C, c’est le moment où il faut regarder tout de suite. Les disques NVMe avaient déjà leur propre règle, à 70 °C ; elle ne bouge pas.
La vérification : le pic de la nuit, rejoué
Une règle réécrite qui « devrait » marcher ne prouve rien. La base de métriques, elle, garde le pic de la nuit précédente. Le 25 octobre à 01:58 UTC, le SSD du worker était à 52 °C. Évaluées à cet instant précis :
| Expression | Résultat au pic |
|---|---|
| Ancienne règle HDD | le SSD du worker |
| Nouvelle règle HDD | rien |
| Nouvelles règles SSD | rien |
smartctl_device_rotation_rate > 0 | les 2 WD Red du NAS |
Disques sd* sans vitesse de rotation | les 5 SSD des Pi |
Le critère classe chaque disque du homelab du bon côté, et l’alerte qui sonnait cette nuit-là n’existe plus avec les nouvelles règles. Dernier contrôle avant de pousser : vmalert -dryRun sur le fichier de règles, sans erreur.
Honnêteté oblige : un pic à 52 °C ne teste pas le chemin « SSD vraiment trop chaud ». Les règles SSD n’ont pas encore été mises à l’épreuve par un vrai dépassement. Le jour où l’une d’elles sonnera, ce sera pour une bonne raison, ou pour une nouvelle leçon.
Leçons retenues
1. Un seuil encode une hypothèse sur le matériel
> 50 °C n’est pas une vérité sur « les disques », c’est une vérité sur les disques durs. Le jour où le matériel change, la règle se trompe sans faire de bruit, puis elle fait beaucoup de bruit. Une migration matérielle (ici, HDD vers SSD) devrait toujours déclencher une relecture des règles qui le concernent.
2. Une heure qui dérive n’est pas un cron
Un événement qui revient chaque jour à une heure légèrement différente ne vient pas d’une tâche planifiée sur l’hôte : celles-ci sont calées sur l’horloge murale. Une dérive régulière de quelques minutes par jour pointe vers une horloge qui ne suit pas NTP, typiquement un firmware. Relever l’heure exacte du symptôme sur deux semaines coûte une requête et élimine une famille entière d’hypothèses.
3. Classer par ce que le matériel est, pas par où il se trouve
Exclure un nœud par son nom aurait marché jusqu’à la prochaine migration. smartctl_device_rotation_rate décrit le disque lui-même et suivra le prochain SSD, le prochain HDD, le prochain nœud, sans retouche.
4. and on / unless on : deux familles, aucun trou
Quand une population se sépare en deux, la même condition utilisée une fois en and et une fois en unless garantit que chaque série tombe dans exactement une règle. Pas de doublon, pas d’oubli.
5. Rejouer le symptôme sur l’historique avant de pousser
La base de métriques garde le pic d’hier. Évaluer l’ancienne et la nouvelle expression à cet instant prouve à la fois que le correctif fait taire le faux positif et que le critère classe correctement chaque disque. C’est plus convaincant que de relire le YAML, et ça ne demande pas d’attendre la nuit suivante.
La limite connue
Un disque dur branché derrière un pont USB qui masque sa vitesse de rotation tomberait dans la famille SSD, avec des seuils trop généreux pour lui. Ce n’est pas le cas aujourd’hui. Si un HDD revient dans le cluster, la première chose à vérifier sera qu’il annonce bien ses tours par minute.
Le canal d’alertes ne sonne plus la nuit. Le SSD, lui, continue son ménage à 52 °C, quelque part entre 1 h et 2 h du matin, et un peu plus tôt chaque jour.