❯ monitoring · Running

Le disque qui chauffait chaque nuit : un cycle de firmware de SSD pris dans un seuil de disque dur The Disk That Ran Hot Every Night: An SSD Firmware Cycle Caught by a Hard-Drive Threshold

Une alerte de température disque sonnait presque chaque nuit sur un worker Raspberry Pi, sans charge, à une heure qui dérivait d'environ deux minutes par jour. En cause : une règle écrite pour des disques à plateaux, appliquée à tous les disques SATA depuis que le dernier HDD a quitté le cluster. Séparer les règles sur la vitesse de rotation rapportée par smartctl a fait taire la nuit sans rendre aveugles les disques du NAS. A disk temperature alert fired almost every night on a Raspberry Pi worker, with no load and at a time that drifted by about two minutes a day. The culprit was a rule written for spinning disks, applied to every SATA device after the last hard drive left the cluster. Splitting the rules on smartctl's rotation rate ended the nightly noise without blinding the NAS drives.

· 7 min de lecture 7 min read ·
monitoringvmalertpromqlsmartssdincident
🇬🇧 Read this article in English

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 pic52 à 53 °C
Durée du picenviron 20 minutes
E/S de l’hôte pendant le picaucune
Tâche planifiée à cette heureaucune
Heure du pic le 11 octobre02:15 UTC
Heure du pic le 25 octobre01: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 :

  1. 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.
  2. 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.

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 :

ExpressionRésultat au pic
Ancienne règle HDDle SSD du worker
Nouvelle règle HDDrien
Nouvelles règles SSDrien
smartctl_device_rotation_rate > 0les 2 WD Red du NAS
Disques sd* sans vitesse de rotationles 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.

monitoringvmalertpromqlsmartssdincident