ClickHouse (Plausible) écrit dans un volume au journal ext4 abandonné depuis le 04/09 : erreurs d'E/S en boucle — constat, rien de réparé #53

Open
opened 2026-09-15 12:02:18 +02:00 by arcodange · 3 comments
Owner

Constat (2026-09-15, 09:53–10:02Z, lecture seule)

Trouvé en balayant les compteurs d'erreurs ext4 des trois nœuds pendant tools#49.

  • Volume : pvc-1251909b-3cef-40c6-881c-3bb6e929a596 (PVC tools/clickhouse-storage-clickhouse-0, 16 Gi, 1,64 Gi utilisés).
    • Attaché sur pi3, où il apparaît comme /dev/sdk.
    • Longhorn le voit healthy, avec trois répliques running (pi1, pi2, pi3).
  • Noyau de pi3 : /sys/fs/ext4/sdk/errors_count = 2.
    • Première erreur 2026-09-04T02:42:40Z (ext4_check_bdev_write_error), dernière à 02:42:47Z (ext4_journal_check_start) : le journal a été abandonné.
    • /proc/mounts affiche encore rw, mais les écritures échouent.
    • Le journal noyau de cette date n'est plus lisible (rotation), donc la cause du 04/09 n'est pas établie. Elle n'est pas forcément liée à pi2.
  • clickhouse-0 : 1/1 Running, 10 redémarrages (le dernier il y a 15 jours).
    • ≈ 40 000 lignes de journal en 10 min, dont 1 521 portent errno: 5, strerror: Input/output error : fusions MergeTree en échec, create_directories: Input/output error.
  • ArgoCD : clickhouse est Healthy, et plausible est Degraded.
  • Conséquence probable : Plausible n'enregistre plus rien de fiable depuis 11 jours. Non vérifié côté Plausible.

Remède probable (non appliqué, exige l'accord du fondateur)

C'est le même que tools#49 (PR #50 et #51) : recréer le pod pour que le volume se démonte et se remonte, de préférence sur un autre nœud que pi3. kubelet lance alors fsck -a et ext4 rejoue son journal.

⚠ Deux différences avec les cas précédents :

  • StatefulSet RollingUpdate : le pod est supprimé avant d'être recréé, donc pas de Multi-Attach. En revanche, il faut vérifier qu'il ne revient pas sur le montage de staging de pi3.
  • Onze jours d'écritures refusées : ClickHouse peut avoir des parts incomplètes à écarter au redémarrage. Il faut relire son journal de démarrage avant de conclure.

Si le remontage échoue sur des erreurs ext4 : pas de fsck en écriture sans accord.

Refs arcodange-org/tools#49 · terrain : arcodange-org/tools#52

🤖 Generated with Claude Code

## Constat (2026-09-15, 09:53–10:02Z, lecture seule) Trouvé en balayant les compteurs d'erreurs ext4 des trois nœuds pendant tools#49. - **Volume** : `pvc-1251909b-3cef-40c6-881c-3bb6e929a596` (PVC `tools/clickhouse-storage-clickhouse-0`, 16 Gi, 1,64 Gi utilisés). - Attaché sur **pi3**, où il apparaît comme `/dev/sdk`. - Longhorn le voit `healthy`, avec trois répliques `running` (pi1, pi2, pi3). - **Noyau de pi3** : `/sys/fs/ext4/sdk/errors_count = 2`. - Première erreur **2026-09-04T02:42:40Z** (`ext4_check_bdev_write_error`), dernière à 02:42:47Z (`ext4_journal_check_start`) : le journal a été abandonné. - `/proc/mounts` affiche encore `rw`, mais les écritures échouent. - Le journal noyau de cette date n'est plus lisible (rotation), donc la cause du 04/09 n'est **pas établie**. Elle n'est pas forcément liée à pi2. - **`clickhouse-0`** : `1/1 Running`, 10 redémarrages (le dernier il y a 15 jours). - **≈ 40 000 lignes de journal en 10 min**, dont 1 521 portent `errno: 5, strerror: Input/output error` : fusions MergeTree en échec, `create_directories: Input/output error`. - **ArgoCD** : `clickhouse` est `Healthy`, et **`plausible` est `Degraded`**. - **Conséquence probable** : Plausible n'enregistre plus rien de fiable depuis **11 jours**. Non vérifié côté Plausible. ## Remède probable (non appliqué, exige l'accord du fondateur) C'est le même que tools#49 (PR #50 et #51) : recréer le pod pour que le volume se démonte et se remonte, de préférence sur **un autre nœud** que pi3. kubelet lance alors `fsck -a` et ext4 rejoue son journal. ⚠ Deux différences avec les cas précédents : - **StatefulSet `RollingUpdate`** : le pod est supprimé avant d'être recréé, donc pas de Multi-Attach. En revanche, il faut vérifier qu'il ne revient pas sur le montage de staging de pi3. - **Onze jours d'écritures refusées** : ClickHouse peut avoir des parts incomplètes à écarter au redémarrage. Il faut relire son journal de démarrage avant de conclure. Si le remontage échoue sur des erreurs ext4 : **pas de fsck en écriture sans accord.** Refs arcodange-org/tools#49 · terrain : arcodange-org/tools#52 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Réparé (12:24) : ClickHouse sur pi1, ext4 remonté, Plausible Healthy

Accord du fondateur : « Oui, même remède, sans perte ».

Geste

  • PR #54 : clickhouse/clickhouseValues.yaml, exclusion requise de pi2 conservée, préférence de poids 100 pour pi1.
  • Rendu kubectl kustomize --enable-helm comparé avant/après : seul ce bloc change.
  • La CI n'a exécuté que « Detect changed charts » (succès). clickhouse/ est une kustomization et ne figure pas dans la matrice « Application charts ». La vérification du rendu est donc la mienne, faite en local.
  • Fusionnée en squash : 8b0cae5af0811931c5fb4e3ff95285191d148d2f.
  • ArgoCD a synchronisé seul à 10:20:17Z.

Bascule (UTC)

  • 10:20:16 : pi3 démonte EXT4-fs (sdk): unmounting filesystem 300fc0b9…, c'est-à-dire le montage mort.
  • Refus transitoires attendus : Multi-Attach, puis not ready for workloads.
  • 10:20:50 : sur pi1, le plugin CSI journalise Device … has errors which were corrected by fsck. C'est le fsck -a automatique de kubelet (mode preen), pas un geste manuel.
  • 10:20:51 : pi1 journalise EXT4-fs (sdb): mounted filesystem 300fc0b9… r/w. /proc/mounts est en rw, et aucun compteur d'erreurs ext4 non nul sur pi1.
  • 10:21:24 : clickhouse-0 est 1/1 Ready sur pi1. Volume attached pi1 healthy.

État vérifié

  • ClickHouse :
    • 0 Input/output error depuis le démarrage (96 lignes de journal, et 0 E/S sur les 5 dernières minutes à 10:24Z) ;
    • 6 lignes <Error>, toutes sur system.processors_profile_log, la table interne de profilage de ClickHouse. Deux parts de 0 octet y ont été écartées automatiquement dans detached/ (broken-on-start) ;
    • rien de supprimé ;
    • system.detached_parts ne contient aucune part de la base plausible.
  • plausible.schema_migrations (la table illisible qui faisait planter l'init) se relit : 32 lignes, dernière version 20240829092858.
  • Plausible :
    • le pod neuf plausible-5bd7b67c95-xk4kt est 2/2 Running sur pi1 ;
    • https://analytics.arcodange.lab/api/health rend 200 ;
    • au démarrage, il journalise [geolocation] database failed to load (:filesystem): :not_found. C'est la base de géolocalisation (sidecar geoip) et ce n'est pas lié au volume.
  • ArgoCD : clickhouse Synced / Healthy, plausible Synced / Healthy (Degraded avant).

Ce qui a été perdu (lecture seule, SELECT uniquement)

Relevé Valeur
Dernier événement écrit (events_v2.timestamp) 2026-09-03 16:04:49
Dernière session (sessions_v2.start) 2026-09-03 15:59:46
Dernière part écrite (system.parts, base plausible) events_v2 2026-09-03 16:53:45 · sessions_v2 16:50:36 · ingest_counters 16:04:59
Total conservé 1 077 événements (depuis le 2026-01-03), 291 sessions
Volume habituel avant la panne 5 à 94 événements par jour du 25/08 au 03/09 (médiane ≈ 43)
  • Trou de statistiques : du 03/09 ~16:05 au 15/09 ~10:21, soit environ 12 jours.
  • À ce rythme, cela représente de l'ordre de 500 événements jamais écrits. C'est une estimation, et ils ne sont pas récupérables.
  • Le dernier événement précède de ~10 h l'erreur ext4 (04/09 02:42Z). Ce silence est compatible avec une nuit sans visite, mais rien ne permet de le distinguer d'un arrêt plus précoce.

Ce qui reste

  • Les 19 parts détachées des tables system.* restent sur le volume, soit quelques octets. Ce sont des journaux internes de ClickHouse. Rien n'a été supprimé.
  • Aucun nouvel événement n'a encore été observé : cela dépend du trafic réel, et je n'ai pas injecté de visite fictive. Pour vérifier, relire plus tard SELECT max(timestamp) FROM plausible.events_v2.

Je laisse l'issue ouverte jusqu'au premier événement neuf observé.

🤖 Generated with Claude Code

## Réparé (12:24) : ClickHouse sur pi1, ext4 remonté, Plausible Healthy Accord du fondateur : « Oui, même remède, sans perte ». ### Geste - **PR #54** : `clickhouse/clickhouseValues.yaml`, exclusion requise de pi2 conservée, préférence de poids 100 pour pi1. - Rendu `kubectl kustomize --enable-helm` comparé avant/après : seul ce bloc change. - ⚠ **La CI n'a exécuté que « Detect changed charts »** (succès). `clickhouse/` est une kustomization et ne figure pas dans la matrice « Application charts ». La vérification du rendu est donc la mienne, faite en local. - **Fusionnée en squash : `8b0cae5af0811931c5fb4e3ff95285191d148d2f`**. - ArgoCD a synchronisé seul à 10:20:17Z. ### Bascule (UTC) - **10:20:16** : pi3 démonte `EXT4-fs (sdk): unmounting filesystem 300fc0b9…`, c'est-à-dire le montage mort. - Refus transitoires attendus : `Multi-Attach`, puis `not ready for workloads`. - **10:20:50** : sur pi1, le plugin CSI journalise `Device … has errors which were corrected by fsck`. C'est le `fsck -a` automatique de kubelet (mode *preen*), pas un geste manuel. - **10:20:51** : pi1 journalise `EXT4-fs (sdb): mounted filesystem 300fc0b9… r/w`. `/proc/mounts` est en `rw`, et aucun compteur d'erreurs ext4 non nul sur pi1. - **10:21:24** : `clickhouse-0` est `1/1 Ready` sur **pi1**. Volume `attached pi1 healthy`. ### État vérifié - **ClickHouse** : - **0 `Input/output error`** depuis le démarrage (96 lignes de journal, et 0 E/S sur les 5 dernières minutes à 10:24Z) ; - 6 lignes `<Error>`, **toutes sur `system.processors_profile_log`**, la table interne de profilage de ClickHouse. Deux parts de **0 octet** y ont été écartées automatiquement dans `detached/` (`broken-on-start`) ; - rien de supprimé ; - `system.detached_parts` ne contient **aucune part de la base `plausible`**. - **`plausible.schema_migrations`** (la table illisible qui faisait planter l'init) se relit : 32 lignes, dernière version `20240829092858`. - **Plausible** : - le pod neuf `plausible-5bd7b67c95-xk4kt` est `2/2 Running` sur pi1 ; - `https://analytics.arcodange.lab/api/health` rend 200 ; - au démarrage, il journalise `[geolocation] database failed to load (:filesystem): :not_found`. C'est la base de géolocalisation (sidecar `geoip`) et ce n'est pas lié au volume. - **ArgoCD** : `clickhouse` Synced / Healthy, **`plausible` Synced / Healthy** (Degraded avant). ### Ce qui a été perdu (lecture seule, `SELECT` uniquement) | Relevé | Valeur | |---|---| | Dernier événement écrit (`events_v2.timestamp`) | **2026-09-03 16:04:49** | | Dernière session (`sessions_v2.start`) | 2026-09-03 15:59:46 | | Dernière part écrite (`system.parts`, base `plausible`) | `events_v2` 2026-09-03 16:53:45 · `sessions_v2` 16:50:36 · `ingest_counters` 16:04:59 | | Total conservé | 1 077 événements (depuis le 2026-01-03), 291 sessions | | Volume habituel avant la panne | 5 à 94 événements par jour du 25/08 au 03/09 (médiane ≈ 43) | - **Trou de statistiques : du 03/09 ~16:05 au 15/09 ~10:21, soit environ 12 jours.** - À ce rythme, cela représente de l'ordre de **500 événements jamais écrits**. C'est une estimation, et ils ne sont pas récupérables. - Le dernier événement précède de ~10 h l'erreur ext4 (04/09 02:42Z). Ce silence est compatible avec une nuit sans visite, mais rien ne permet de le distinguer d'un arrêt plus précoce. ### Ce qui reste - Les 19 parts détachées des tables `system.*` restent sur le volume, soit quelques octets. Ce sont des journaux internes de ClickHouse. Rien n'a été supprimé. - Aucun nouvel événement n'a encore été observé : cela dépend du trafic réel, et je n'ai pas injecté de visite fictive. Pour vérifier, relire plus tard `SELECT max(timestamp) FROM plausible.events_v2`. Je laisse l'issue ouverte jusqu'au premier événement neuf observé. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

⚠ Plausible est retombé à 11:08Z, et la cause n'est pas le volume (13:20)

Constat en lecture seule, rien d'appliqué.

Chronologie

  • 10:46Z : la rotation des identifiants de base de données de Plausible (redémarrage demandé par l'opérateur Vault) crée une nouvelle révision. Son pod est placé sur pi2.
  • 10:49Z : le pod est disponible. ArgoCD le voit alors Healthy.
  • 11:08Z : le Deployment perd sa disponibilité minimale. Le conteneur plausible boucle depuis : CrashLoopBackOff, 13 redémarrages en 30 min, code 137. Un départ relevé à 11:14:05 a été tué à 11:15:01, par la sonde de vivacité (Container plausible failed liveness probe, will be restarted).
  • ArgoCD : plausible en Progressing.

Faits

  • Aucune ligne de journal dans le conteneur, ni courant ni précédent.
  • Les sondes font /api/health, avec un délai d'1 s, 3 échecs tolérés, sans sonde de démarrage.
  • L'init init-database s'est terminée en code 0 : la migration ClickHouse passe.
  • ClickHouse est sain : clickhouse-0 sur pi1, 0 Input/output error sur les 20 dernières minutes.
  • La base répond : pgbouncer voit les connexions du pod s'ouvrir, puis se fermer en client unexpected eof à la mort du conteneur.
  • pi2 dispose de 4,2 Gi de mémoire (free -m, colonne available), et son CPU a varié de 59 à 110 % dans la matinée.

Hypothèse, non prouvée : le démarrage de Plausible sur pi2 dépasse la fenêtre de la sonde (1 s × 3 essais, sans sonde de démarrage), et le conteneur est tué avant d'écouter. Les révisions précédentes démarraient sur pi1 et pi3.

À décider :

  1. ajouter une sonde de démarrage patiente dans le chart plausible/ du dépôt tools (même forme que Loki, #45) ;
  2. et/ou éviter pi2 pour Plausible.

Rien n'a été modifié.

Je laisse l'issue ouverte : pas de premier événement neuf observé, et Plausible est à nouveau indisponible.

🤖 Generated with Claude Code

## ⚠ Plausible est retombé à 11:08Z, et la cause n'est pas le volume (13:20) Constat en lecture seule, **rien d'appliqué**. **Chronologie** - **10:46Z** : la rotation des identifiants de base de données de Plausible (redémarrage demandé par l'opérateur Vault) crée une nouvelle révision. Son pod est placé sur **pi2**. - **10:49Z** : le pod est disponible. ArgoCD le voit alors `Healthy`. - **11:08Z** : le Deployment perd sa disponibilité minimale. Le conteneur `plausible` **boucle** depuis : `CrashLoopBackOff`, 13 redémarrages en 30 min, code **137**. Un départ relevé à 11:14:05 a été tué à 11:15:01, par la sonde de vivacité (`Container plausible failed liveness probe, will be restarted`). - ArgoCD : `plausible` en `Progressing`. **Faits** - **Aucune ligne de journal** dans le conteneur, ni courant ni précédent. - Les sondes font `/api/health`, avec un délai d'**1 s**, 3 échecs tolérés, **sans sonde de démarrage**. - L'init `init-database` s'est terminée en **code 0** : la migration ClickHouse passe. - **ClickHouse est sain** : `clickhouse-0` sur pi1, 0 `Input/output error` sur les 20 dernières minutes. - **La base répond** : pgbouncer voit les connexions du pod s'ouvrir, puis se fermer en `client unexpected eof` à la mort du conteneur. - pi2 dispose de 4,2 Gi de mémoire (`free -m`, colonne *available*), et son CPU a varié de 59 à 110 % dans la matinée. **Hypothèse, non prouvée** : le démarrage de Plausible sur pi2 dépasse la fenêtre de la sonde (1 s × 3 essais, sans sonde de démarrage), et le conteneur est tué avant d'écouter. Les révisions précédentes démarraient sur pi1 et pi3. **À décider** : 1. ajouter une sonde de démarrage patiente dans le chart `plausible/` du dépôt tools (même forme que Loki, #45) ; 2. et/ou éviter pi2 pour Plausible. Rien n'a été modifié. Je laisse l'issue ouverte : pas de premier événement neuf observé, et Plausible est à nouveau indisponible. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Plausible réparé (14:17) : sonde de démarrage patiente et hors de pi2

Accord du fondateur : « Les deux : un délai de démarrage patient et éviter pi2 ».

Geste

PR #55, fusionnée en squash (adc4aee), deux blocs seulement :

  1. une startupProbe sur /api/health : période 10 s, 60 échecs tolérés (10 min), délai 5 s. Même forme que Loki (#45). Posée par patch kustomize, car le chart n'expose pas ses sondes. La vivacité et la disponibilité sont inchangées ;
  2. une exclusion requise de pi2, même forme que ClickHouse (#54). C'est la forme la plus simple, et elle ne bloque le placement que si pi1 et pi3 tombent.

Vérifications avant la fusion

  • Rendu kubectl kustomize --enable-helm plausible/ avant/après : seuls ces deux blocs changent.
  • CI : seule « Detect changed charts » s'exécute (succès), car plausible/ est une kustomization hors de la matrice.

Constat avant la fusion : le pod de pi2 s'était relevé seul après 20 redémarrages. Il était 2/2 depuis 11:38Z, et sa dernière sortie était en code 0. L'hypothèse de lenteur au démarrage en sort renforcée : il finissait par passer, parfois. La fusion a eu lieu comme décidé.

Bascule (UTC)

  • ArgoCD a synchronisé seul à 12:03:51Z. Rien n'a été forcé.
  • Le pod neuf est placé sur pi3 : init terminé à 12:04:14, conteneur plausible démarré à 12:04:17.
  • La sonde de démarrage a échoué 2 fois (12:04:22 et 12:04:32, connection refused). C'est exactement la fenêtre où, auparavant, la vivacité tuait le conteneur.
  • Ready=True à 12:04:42, soit 25 s après le départ du conteneur.
  • L'ancien pod de pi2 a été arrêté par la bascule.

Vérifié

Contrôle Résultat
Pod neuf Ready, hors de pi2 2/2 Running sur pi3
Aucun redémarrage pendant au moins 10 min relevé toutes les 30 s de 12:04:17 à 12:15:01 : 0 redémarrage, toujours ready=true, aucun événement Killing ni BackOff
https://analytics.arcodange.lab/api/health 200, trois fois (0,11 s, 0,04 s, 0,04 s)
ArgoCD plausible Synced / Healthy sur adc4aee
Pods Plausible dans le namespace 1

L'hypothèse de lenteur tient : hors de pi2, et avec une sonde de démarrage, le pod est prêt en 25 s et ne redémarre plus.

Reste

  • Aucun nouvel événement Plausible n'a encore été relu dans ClickHouse. Cela dépend du trafic réel, et aucune visite fictive n'a été injectée.
  • Les deux dossiers .empty d'url-shortener restent en place, comme demandé.

L'issue reste ouverte jusqu'au premier événement neuf.

🤖 Generated with Claude Code

## Plausible réparé (14:17) : sonde de démarrage patiente et hors de pi2 Accord du fondateur : « Les deux : un délai de démarrage patient et éviter pi2 ». ### Geste **PR #55**, fusionnée en squash (`adc4aee`), deux blocs seulement : 1. une **`startupProbe`** sur `/api/health` : période 10 s, 60 échecs tolérés (10 min), délai 5 s. Même forme que Loki (#45). Posée par patch kustomize, car le chart n'expose pas ses sondes. La vivacité et la disponibilité sont inchangées ; 2. une **exclusion requise de pi2**, même forme que ClickHouse (#54). C'est la forme la plus simple, et elle ne bloque le placement que si pi1 **et** pi3 tombent. **Vérifications avant la fusion** - Rendu `kubectl kustomize --enable-helm plausible/` avant/après : seuls ces deux blocs changent. - CI : seule « Detect changed charts » s'exécute (succès), car `plausible/` est une kustomization hors de la matrice. ⚠ **Constat avant la fusion** : le pod de pi2 s'était relevé seul après 20 redémarrages. Il était `2/2` depuis 11:38Z, et sa dernière sortie était en code 0. L'hypothèse de lenteur au démarrage en sort renforcée : il finissait par passer, parfois. La fusion a eu lieu comme décidé. ### Bascule (UTC) - ArgoCD a synchronisé **seul** à 12:03:51Z. Rien n'a été forcé. - Le pod neuf est placé sur **pi3** : init terminé à 12:04:14, conteneur `plausible` démarré à 12:04:17. - La **sonde de démarrage** a échoué **2 fois** (12:04:22 et 12:04:32, `connection refused`). C'est exactement la fenêtre où, auparavant, la vivacité tuait le conteneur. - **`Ready=True` à 12:04:42**, soit 25 s après le départ du conteneur. - L'ancien pod de pi2 a été arrêté par la bascule. ### Vérifié | Contrôle | Résultat | |---|---| | Pod neuf `Ready`, hors de pi2 | `2/2 Running` sur **pi3** | | Aucun redémarrage pendant au moins 10 min | relevé toutes les 30 s de 12:04:17 à 12:15:01 : **0 redémarrage**, toujours `ready=true`, aucun événement `Killing` ni `BackOff` | | `https://analytics.arcodange.lab/api/health` | **200**, trois fois (0,11 s, 0,04 s, 0,04 s) | | ArgoCD `plausible` | **Synced / Healthy** sur `adc4aee` | | Pods Plausible dans le namespace | 1 | **L'hypothèse de lenteur tient** : hors de pi2, et avec une sonde de démarrage, le pod est prêt en 25 s et ne redémarre plus. ### Reste - Aucun nouvel événement Plausible n'a encore été relu dans ClickHouse. Cela dépend du trafic réel, et aucune visite fictive n'a été injectée. - Les deux dossiers `.empty` d'url-shortener restent en place, comme demandé. L'issue reste ouverte jusqu'au premier événement neuf. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: arcodange-org/tools#53