Commit Graph
9 Commits
Author SHA1 Message Date
arcodange 88e0f5e862 Prometheus n'a rien enregistré pendant 3 jours, et rien ne pouvait le dire
Helm Charts / Library charts tool (pull_request) Skipped
Helm Charts / Application charts chart (pull_request) Skipped
Helm Charts / Application charts prometheus (pull_request) Failing after 7s
Helm Charts / Detect changed charts (pull_request) Successful in 19s
Helm Charts / Application charts crowdsec (pull_request) Skipped
Helm Charts / Application charts grafana (pull_request) Skipped
Helm Charts / Application charts hashicorp-vault (pull_request) Skipped
Helm Charts / Application charts minio (pull_request) Skipped
Helm Charts / Application charts pgbouncer (pull_request) Skipped
Helm Charts / Application charts pgcat (pull_request) Skipped
Helm Charts / Application charts redis (pull_request) Skipped
Du 2026-09-04 02:41 au 2026-09-07 07:37, le WAL de Prometheus était sur un
système de fichiers passé en lecture seule. Pendant 3 j 5 h il a continué de
scruter ses 23 cibles et de JETER le résultat. Les 11 règles d'alerte du dépôt
n'ont rien dit — elles vivent DANS ce Prometheus, elles évaluent des requêtes
contre le TSDB qui ne recevait plus rien, et sans échantillon frais une règle
ne se déclenche pas : elle SE TAIT. Sur Telegram, le silence d'une alerte est
indiscernable du bon fonctionnement.

⚠⚠ AJOUTER UNE RÈGLE « PROMETHEUS VA MAL » NE CORRIGE RIEN : elle serait muette
exactement quand il faudrait qu'elle parle. C'est le gate incapable d'échouer,
celui qui rassure. Ce lot pose donc un guetteur HORS de Prometheus.

Ce qui est livré
----------------
1. `prometheus/veilleur/veilleur.py` + un CronJob `*/5` (templates/veilleur.yaml,
   rendu tel quel par ArgoCD comme vault-telegram.yaml). Il interroge Prometheus
   depuis dehors et POUSSE LUI-MÊME sur Telegram, sans passer par Alertmanager.
   Jeton et salon viennent du Secret `alertmanager-telegram` DÉJÀ synchronisé
   depuis Vault — aucun second chemin de secret, aucun jeton en clair.
2. Le témoin toujours allumé `Veilleur` (`expr: vector(1)`) et sa route vers un
   récepteur VIDE : il ne sonne jamais, il est là pour être CONSTATÉ dans
   /api/v2/alerts par le guetteur. ⚠ Il ne lit aucune série : il aurait continué
   de tirer pendant les 3 j 5 h. Il prouve la chaîne d'alerte, jamais le TSDB.
3. `VeilleurMuet`, l'auto-plainte : le guetteur pousse un battement au
   Pushgateway ; la règle crie quand il vieillit de plus de 20 min.

⚠⚠ LE PIÈGE, ÉCRIT DANS LE CODE À L'ENDROIT OÙ ON VOUDRA SIMPLIFIER : pendant la
panne, /-/healthy rendait 200, /api/v1/targets annonçait 23 cibles presque
toutes `up`, le pod était Running 2/2 avec 0 redémarrage, Longhorn se disait
`healthy` — et `count(up)` ne rendait AUCUNE SÉRIE. Un veilleur branché sur
/-/healthy n'aurait rien vu ; un veilleur qui lit `resultat[0]` sans regarder
serait tombé dans la branche « rien à signaler ». LE VECTEUR VIDE EST L'ALARME.
Et il l'est structurellement : `--query.lookback-delta` vaut 5 min, donc au-delà
de 5 min de retard `up` ne rend PLUS RIEN — la branche « âge > seuil » ne peut
mesurer qu'entre 0 et 5 min, jamais une panne de trois jours.

La propriété gardée, et son arithmétique
----------------------------------------
« Si Prometheus cesse d'enregistrer, une notification arrive en ≤ 8 min 10 s. »

  seuil de fraîcheur      180 s  (3 × `scrape_interval: 1m`)
  période du CronJob      300 s  (*/5, pire cas : on vient de manquer un tour)
  tolérance au roulement  180 s  (2 × 90 s — un redéploiement ne réveille personne)
  exécution                 ~7 s (mesuré)
  ------------------------------
  au pire                 487 s  contre 4 620 minutes de silence réel.

Les deux premiers termes ne s'additionnent pas : le seuil est absorbé par le
vecteur vide dès la première observation.

MESURÉ, deux fois, sur la planification RÉELLE et avec le cas (c) armé dans le
CronJob déployé : du top de la planification au « Telegram a accepté »,
**187 s** (08:20:00 → 08:23:07, puis 08:30:02 → 08:33:09). Les 300 s d'attente
du tour suivant ne sont PAS mesurées — elles dépendent de la phase à laquelle la
panne commence ; elles sont bornées par le `schedule`.

SABOTAGES — le banc unitaire (`python3 -m unittest discover -s prometheus/veilleur`)
------------------------------------------------------------------------------------
Il rejoue les réponses HTTP MESURÉES pendant l'incident. ⚠ Ce qu'il ne rejoue
PAS : la couche ext4/Longhorn qui a causé la panne — il rejoue la SURFACE que
la panne présentait, c'est-à-dire tout ce qu'un guetteur extérieur peut voir.

  | sabotage                                          | code | ce qui rougit                    | ce qui reste vert |
  |---------------------------------------------------|------|----------------------------------|-------------------|
  | (aucun)                                           |  0   | —                                | 8/8               |
  | S-A : on ignore le vecteur vide dans `observer()` |  1   | cas (c), auto-plainte            | le silence nominal |
  | S-B : `age > -1` — il crie tout le temps          |  1   | le silence nominal, la tolérance | les 6 alarmes     |
  | S-C : route `Veilleur` → telegram au lieu de néant|  1   | l'assertion jq de la CI          | —                 |
  | promtool `exp_alerts: []` sur le témoin           |  1   | le test de règle                 | —                 |

⚠ La première tentative de S-A n'a PAS mordu comme prévu : elle a rougi sur une
erreur de schéma YAML, pas sur l'assertion. Refaite pour être un vrai échec
d'assertion. Un sabotage dont on ne vérifie pas qu'il mord au bon endroit rend
un « rouge » qui ne prouve rien.

⚠⚠ ET LA GATE EST CÂBLÉE : elle tourne dans `.gitea/workflows/helmcharts.yaml`,
dans le job qui construit déjà le chart prometheus, à chaque PR qui le touche.
Une gate que la CI ne déclenche jamais est la cinquième forme du gate qui
rassure.

SABOTAGES — en vrai, sur le cluster (vrais Jobs, vrai Telegram)
---------------------------------------------------------------
  | # | mode                      | comment                                        | verdict                          | code | délai   |
  |---|---------------------------|------------------------------------------------|----------------------------------|------|---------|
  |L6 | nominal                   | rien                                           | SE TAIT, 0 message               |  0   | 18,7 s  |
  |L1 | (a) Prometheus MORT       | `scale deploy prometheus-server --replicas=0`   | crie « injoignable »             |  0   | 50 s    |
  |L4 | (a) variante simple       | URL vers un hôte inexistant                    | crie « injoignable »             |  0   |  8,4 s  |
  |L3 | (b) données périmées      | requête rendant 277 500 s                      | crie « retarde », « 3 j 5 h »    |  0   | 11,5 s  |
  |L2 | (c) LE DÉFAUT RÉEL        | sélecteur vide sur un Prometheus SAIN          | crie « n'enregistre RIEN »       |  0   | 31,5 s  |
  |L5a| témoin présent            | `ALERTE_TEMOIN` = une alerte vraiment active   | SE TAIT                          |  0   |  8,6 s  |
  |L5b| témoin absent             | `ALERTE_TEMOIN` = un nom inexistant            | crie « chaîne muette »           |  0   |  8,4 s  |
  |L7 | auto-plainte              | Telegram injoignable + cas (c)                 | Job **Failed**, AUCUN battement  |  2   | 12,6 s  |

Le message de L2 portait la contradiction elle-même : « 23 cibles actives,
21 annoncées `up` » en face de zéro série — le chiffre exact du matin.

⚠ CE QUE L1 NE REJOUE PAS : descendre le déploiement à 0 rend Prometheus
injoignable, pas MENTEUR. Le défaut réel — répondre parfaitement en
n'enregistrant rien — n'est PAS reproductible par un `scale` ; il l'est par L2,
contre un Prometheus en pleine santé.

Prometheus après les essais
---------------------------
Remonté à 08:13:50Z, prêt à 08:14:08Z (18 s). Montage `rw`, 0 « input/output
error » et 0 `level=ERROR` dans ses journaux, `count(up)` = 23 séries, fraîcheur
du dernier point 0,94 s, `kadans_jobs_jobs` = 8 séries.

⚠ EFFET DE BORD ASSUMÉ ET NON RÉPARÉ : le pod a été replanifié de pi3 vers pi1.
Le commentaire du groupe `homelab` de ce même fichier affirme « Prometheus vit
sur pi3 et Alertmanager sur pi2 : cette chaîne d'alerte survit donc à la perte
de pi1 ». Ce n'est plus vrai. Un `kubectl -n tools delete pod` le rejoue, sans
garantie d'atterrissage. Le veilleur, lui, est un CronJob : il n'est lié à aucun
nœud.

Ce que ce lot ne couvre PAS
---------------------------
- La CAUSE du passage en lecture seule reste inconnue (issue #36) : ce lot
  surveille le symptôme, pas le disque.
- « Le veilleur en panne ET Prometheus en panne » : les deux moitiés de
  l'auto-plainte finissent sur Telegram, donc un Telegram cassé les emporte
  toutes les deux. Il faudrait un second canal, indépendant de ce homelab.
- `prometheus/.helmignore` est ajouté au passage : l'étape de publication du
  chart fait `tar -X <chart>/.helmignore`, qui échouerait sur un chart qui n'en
  a pas. `grafana` et `redis` sont dans le même cas — pas traités ici.

Refs: arcodange-org/tools#36

Remise en état
--------------
Tous les objets d'essai ont été retirés du cluster (8 Jobs, le Job planifié, le
CronJob, son ConfigMap, le groupe `veilleur-prometheus` du Pushgateway, et les
trois fichiers écrits sur le volume Prometheus pour `promtool`). Le veilleur
n'est donc PAS en service : c'est la fusion de cette PR qui le déploiera, par
ArgoCD. Rien n'a été appliqué avec Tofu, aucun workflow Vault n'a été déclenché.
2026-09-07 10:35:10 +02:00
arcodangeandClaude Fable 5 347ebee1b0 feat(observabilité) — jobs d'analyse Kadans : scrape du worker LAPTOP + dashboard Grafana
Helm Charts / Detect changed charts (push) Successful in 1m10s
Helm Charts / Detect changed charts (pull_request) Successful in 1m1s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
- prometheus : cible statique kadans-worker-mac (192.168.1.103:9105, tier
  laptop). Un scrape raté n'est PAS un incident : le Mac dort, up==0 raconte
  la latence — ne pas alerter dessus. ⚠ réserver l'IP au routeur (DHCP).
- grafana : provider + dashboard « Kadans — jobs d'analyse » (uid
  kadans-jobs-analyse) : worker en écoute / dernier poll / file pending + âge
  du plus ancien (seuils 1 h / 24 h = le SLO), file par statut et publications
  par issue (couleurs de STATUT sémantiques), lanes exécutées et durée moyenne
  par lane. La façade, elle, arrive par les annotations de son pod
  (kadans-jobs#3) — zéro config ici.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-24 21:17:06 +02:00
arcodangeandClaude Fable 5 6f398f4ddc feat(alerting): 5e règle homelab — CertificatNonRenouvele (<4 h restantes)
Helm Charts / Detect changed charts (pull_request) Successful in 22s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 1m8s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Les 4 premières règles n'auraient rien vu le matin du 2026-07-24 : nœuds up,
traefik up… mais wildcard 24 h expiré (renouvellement en échec silencieux
depuis des heures). certmanager_certificate_expiration_timestamp_seconds est
déjà scrapée (vérifié live : 2 séries). Cert-manager renouvelle à ~16 h d'âge ;
<4 h restantes = plusieurs cycles ratés → critical, 15 min de grâce.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-24 10:17:18 +02:00
arcodangeandClaude Fable 5 b9626d878b feat(alerting): groupe homelab — alerté quand (ou juste avant que) le lab tombe
Helm Charts / Detect changed charts (pull_request) Successful in 2m2s
Helm Charts / Detect changed charts (push) Successful in 10m9s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Incident 2026-07-23 : un build CI sans limites a épuisé la RAM de pi1 (0 swap),
load15 >100, traefik + apiserver affamés → tout *.arcodange.lab injoignable,
Gitea compris (pourtant sain sur pi2). Personne n'est prévenu : on subit.

Quatre règles, livrées par la chaîne Telegram déjà en place (testée live) :
- NoeudInjoignable (critical) : node-exporter muet 3 min — nœud down ou noyé.
- IngressLabIndisponible (critical) : 0 replica traefik dispo, ou métrique
  absente (kube-state-metrics vit sur pi1) — *.arcodange.lab est HS.
- NoeudPressionMemoire (warning) : <500 Mo dispo 5 min — le précurseur exact
  de l'incident, déclenche avant le thrash.
- NoeudEnSurcharge (warning) : load15 >8 pendant 10 min.

Exprs validées contre le Prometheus live (parse + match) : pendant la rédaction,
IngressLabIndisponible et NoeudEnSurcharge matchaient l'incident en cours.
Prometheus (pi3) et Alertmanager (pi2) survivent à la perte de pi1.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-24 00:12:37 +02:00
arcodangeandClaude Opus 4.8 8e236230d3 fix(alerting): alerte fiable sur l'échec de la vidéo quotidienne du brief
Helm Charts / Detect changed charts (push) Successful in 2m50s
Helm Charts / Detect changed charts (pull_request) Successful in 18s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
ProspectionBriefNotSent (pushed==0, severity info) ne couvrait que la
livraison et déclenchait à tort quand l'étape brief était volontairement
sautée (metrics.py émet brief_rendered=0 aussi sur skip — seul
step_status{step="brief"} distingue skip(2) d'erreur(0)).

Remplacé par deux règles warning, gardées contre le skip :
- ProspectionBriefFailed : rendered==0 AND step_status{brief}!=2 → la
  PRODUCTION de la vidéo a échoué (TTS/ffmpeg/PIL ou erreur amont) ;
- ProspectionBriefNotSent : pushed==0 AND rendered==1 → vidéo produite
  mais PAS livrée sur Telegram (token/chat_id/API).

Expressions validées en live sur Prometheus (match on(job) prouvé par
requête témoin, les deux exprs vides sur l'état sain du jour). En-tête du
groupe mis à jour : la livraison AM→Telegram est câblée et testée.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-23 22:05:45 +02:00
arcodangeandClaude Opus 4.8 4005d89c0c fix(alerting): VaultAuth Telegram exige vaultConnectionRef dans le ns tools
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Detect changed charts (pull_request) Successful in 15s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
VSO refuse un VaultAuth sans vaultConnectionRef dans le ns tools
(« vaultConnectionRef must be set on resources in the "tools" namespace »),
contrairement au ns prospection qui hérite d'une connexion par défaut. On
référence la VaultConnection `default` déjà présente dans tools. Sans ça, le
Secret alertmanager-telegram n'est jamais synchronisé et le pod Alertmanager
reste bloqué sur le montage manquant.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 23:23:07 +02:00
arcodangeandClaude Opus 4.8 714e2bc2ab feat(alerting): livraison Telegram des alertes via Alertmanager
Helm Charts / Detect changed charts (push) Successful in 14s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 14s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Les règles d'alerte `prospection` s'évaluaient déjà dans Prometheus mais ne
notifiaient nulle part. On câble Alertmanager pour livrer les alertes sur le bot
Telegram de prospection, via `telegram_configs` natif d'Alertmanager.

- iac Vault : policy read-only `alertmanager-telegram` sur
  kvv2/data/prospection/telegram + rôle k8s `alertmanager` (SA
  prometheus-alertmanager, ns tools).
- VSO : VaultAuth + VaultStaticSecret resynchronisent kvv2/prospection/telegram
  vers un Secret `alertmanager-telegram` dans le ns tools (le Secret prospection
  est namespace-scoped, non réutilisable). rolloutRestartTargets sur le
  StatefulSet Alertmanager.
- prometheus values : lien server -> Alertmanager (prometheus-alertmanager:9093),
  route + receiver `telegram` (bot_token_file monté, chat_id inline, parse_mode
  HTML, send_resolved), et montage du Secret via extraSecretMounts.

Additif : ni grafana ni les règles d'alerte existantes ne sont touchés.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 23:20:00 +02:00
arcodangeandClaude Opus 4.8 e6fca752a2 feat(monitoring): dashboard Grafana + règles d'alerte prospection
Helm Charts / Detect changed charts (push) Successful in 22s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Detect changed charts (pull_request) Successful in 21s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Consomme les métriques poussées par le pipeline prospection au Pushgateway
(job=prospection, déjà scrapé). Additif — n'affecte aucun dashboard existant.

- grafana : provider + dashboard « Prospection — pipeline BI missions » inliné
  (grafana.dashboards.prospection, json) — vue d'ensemble (fraîcheur/statut/durée/
  erreurs/missions/score), collecte par étape (table + historique), modèle de
  données (opportunités A/B, offres/entités), livraison (brief/Telegram) + panneau
  Alertes actives. Inline plutôt que ConfigMap externe : grafana est déployé via un
  HelmChart CRD (tool lib), l'inline évite toute hypothèse de namespace.
- prometheus : groupe d'alertes `prospection` (serverFiles.alerting_rules.yml) —
  RunStale (>25h), RunFailed, StepError, NoOffers, BriefNotSent.

NB : la livraison des alertes (Alertmanager → Telegram) n'est pas câblée dans le
cluster (server.alertmanagers vide, aucun receiver) ; les règles restent visibles
dans Prometheus /alerts + le dashboard. Câblage delivery = décision séparée.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-08 19:52:29 +02:00
arcodange a762c8f90f deploy prometheus
Helm Charts / Application charts pgcat (push) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 25s
Helm Charts / Library charts tool (push) Has been skipped
2026-03-18 16:21:31 +01:00