Commit Graph
14 Commits
Author SHA1 Message Date
arcodange d03b323394 CI — le banc passe AVANT le téléchargement des dépendances, et un relevé nomme l'hôte qui ne se résout pas
Helm Charts / Detect changed charts (pull_request) Successful in 17s
Helm Charts / Library charts tool (pull_request) Skipped
Helm Charts / Application charts chart (pull_request) Skipped
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
Helm Charts / Application charts prometheus (pull_request) Failing after 32s
Le tout premier run du job `Application charts prometheus` — le premier depuis
que #32 a énuméré les charts — est mort à l'étape `helm_install_dependencies`,
`curl` code **6** (hôte non résolu), en **7 s**, AVANT toute étape utile. Le
banc du veilleur en est sorti `Skipped` : ni rouge, ni absent, rien ne dépasse.
C'est la forme même du gate qui n'existe pas.

Deux changements, tous deux minimaux :

1. Le banc du veilleur remonte JUSTE APRÈS le checkout. Il n'a besoin ni du
   réseau ni du registre Helm interne (stdlib Python, plus `yq`/`jq` déjà là),
   donc il s'exécute et rend un verdict quoi qu'il arrive ensuite.
2. Un RELEVÉ (jamais une gate : `exit 0` en dur) nomme lequel des deux hôtes
   tombe. **7 charts sur 10 dépendent du registre interne
   `gitea.arcodange.lab`** — crowdsec, grafana, hashicorp-vault, pgbouncer,
   pgcat, prometheus, redis. Si c'est bien lui que le runner ne résout pas,
   alors sept jobs sur dix ne peuvent PAS passer, quel que soit leur contenu :
   un trou d'infrastructure que #32 vient de rendre visible, pas un défaut de
   ce lot. À retirer quand le trou est bouché.

Refs: arcodange-org/tools#36
2026-09-07 10:42:49 +02:00
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
arcodange bb3a5cdf5c MinIO tournait sans une seule sonde — et 8 charts sur 10 n'étaient jamais construits (#32)
Helm Charts / Detect changed charts (push) Successful in 10s
Helm Charts / Library charts tool (push) Skipped
Helm Charts / Application charts chart (push) Skipped
Helm Charts / Application charts crowdsec (push) Skipped
Helm Charts / Application charts grafana (push) Skipped
Helm Charts / Application charts hashicorp-vault (push) Skipped
Helm Charts / Application charts pgbouncer (push) Skipped
Helm Charts / Application charts pgcat (push) Skipped
Helm Charts / Application charts prometheus (push) Skipped
Helm Charts / Application charts redis (push) Skipped
Helm Charts / Application charts minio (push) Failing after 7s
Co-authored-by: Gabriel Radureau <[email protected]>
2026-09-03 00:26:41 +02:00
arcodangeandClaude Opus 5 2bdc486ae6 ci — arrêter les runs qui ne peuvent pas aboutir, et le doublon push+PR
Helm Charts / Detect changed charts (pull_request) Successful in 17s
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Quatre runs d'une branche déjà mergée ont bloqué, ce matin, l'apply qu'on
attendait. Deux causes, indépendantes :

1. Les workflows tofu (minio, vault, crowdsec, plausible) s'authentifient à
   Vault par un flux OIDC dont un HUMAIN doit ouvrir le lien. Déclenchés tout
   seuls, ils ne peuvent qu'occuper un runner jusqu'au timeout. Ils font en
   plus `apply` en `auto_approve` CONTRE LA PROD : partir sur le push d'une
   branche, c'est appliquer du code que personne n'a relu. → `workflow_dispatch`
   seul, ce qui écrit enfin ce qu'ils faisaient déjà.

   (crowdsec et plausible passaient de toute façon par une ancre YAML, donc
   leurs triggers étaient INERTES — issues 113 → 117 de kadans.)

2. `push` sur toutes les branches + `pull_request` = DEUX runs par commit dès
   qu'une branche a une PR. Vérifié : runs 258/259 et 260/261 portent le même
   SHA. helmcharts, qui travaille seul et mérite de rester automatique, prend
   la forme éprouvée de la CI de kadans : push sur `main`, PR pour la branche.

Chaque clé de trigger porte un corps explicite : un `pull_request:` nu n'est
pas une forme éprouvée ici, et son mode d'échec est le silencieux.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-26 12:37:46 +02:00
arcodangeandClaude Opus 5 d146affbcd fix(minio) — déclarer minio dans la liste centrale des applications Vault
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Detect changed charts (push) Successful in 1m6s
Helm Charts / Detect changed charts (pull_request) Successful in 24s
Hashicorp Vault / Auth with gitea for vault (push) Failing after 8m38s
Hashicorp Vault / Tofu - Vault IAC (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
Helm Charts / Library charts tool (push) Has been skipped
Hashicorp Vault / Tofu - Vault IAC (pull_request) Has been skipped
Hashicorp Vault / Auth with gitea for vault (pull_request) Failing after 8m40s
Helm Charts / Application charts pgcat (push) Has been skipped
CI en échec sur le workflow MinIO : role "gitea_cicd_minio" could not be found.

Diagnostic : les rôles CI gitea_cicd_<app> ne naissent PAS dans l'IaC de
l'application — ils viennent du module app_policy, appliqué centralement par
hashicorp-vault/iac pour chaque entrée de terraform.tfvars. J'avais posé
minio/iac (qui s'authentifie AVEC ce rôle) sans alimenter la liste : le run
tentait donc de s'authentifier avec un rôle que personne n'avait créé. Amorçage
circulaire, entièrement de mon fait.

- hashicorp-vault/iac/terraform.tfvars : minio ajouté aux applications, avec
  service_account_namespaces = ["tools"] comme crowdsec et plausible ;
- .gitea/workflows/vault.yaml : les triggers couvrent désormais *.tfvars en
  plus de *.tf. C'est là que vit la liste des applications : sans ça, ajouter
  une app ne déclenchait jamais la création de son rôle — le piège qui vient
  de mordre. Les ancres YAML des triggers sont retirées au passage (une ancre
  dans un trigger Gitea Actions fait taire push ET pull_request en silence,
  vécu sur arcodange/kadans, issues 113→117 ; c'est probablement pourquoi ce
  workflow ne partait qu'à la main) ;
- minio/README.md : l'ordre de mise en service dit maintenant les DEUX étapes
  et nomme l'erreur exacte à laquelle on s'expose en les inversant.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-25 18:23:02 +02:00
arcodangeandClaude Opus 5 84edfc8640 feat(minio) — stockage objet S3 du homelab (brique partagée de tools)
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Detect changed charts (pull_request) Successful in 15s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Library charts tool (pull_request) Has been skipped
MinIO / Tofu - minio IAC (pull_request) Has been skipped
MinIO / Auth with gitea for vault (pull_request) Failing after 8m32s
Helm Charts / Application charts pgcat (pull_request) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
Le fondateur : « on déploie MinIO dans le repo tools du homelab non ? » — oui,
c'est bien le pattern : le dossier tools/ porte les briques PARTAGÉES
(pgbouncer, clickhouse, grafana…) et le namespace tools les fait tourner ; les
charts applicatifs vivent dans le repo de leur app.

Décidé de longue date côté produit, jamais déployé : ADR-012 « MinIO local
d'abord » (bascule R2 à 100+ utilisateurs / 10 To par mois), ADR-013 (le gratuit
reste local-first, MinIO sert les paliers payants). Vérifié avant d'écrire :
aucun pod ni service MinIO dans le cluster.

Le chart suit la recette du repo (dépendance à la library "tool" + chart amont
en SubChart, deux gardes dans templates/) :

- mode STANDALONE, 1 réplique : ce qui transite est DÉRIVÉ (le master d'une
  vidéo reste sur l'appareil de son propriétaire, ADR-018) et Longhorn réplique
  déjà le volume — l'erasure coding distribué coûterait de la RAM que des Pi 5
  n'ont pas à dépenser pour ça ;
- 50 Gi sur longhorn ≈ 250 h de cours au palier « travail » (360p, 3,4 Mo/min) ;
  ⚠ Longhorn réplique : compter ×3 sur la capacité avant d'augmenter ;
- ressources bornées (512 Mi / 2 Gi) : la limite protège les voisins de tools ;
- API s3.arcodange.lab + console minio.arcodange.lab (Traefik) ;
- bucket kadans-videos PRIVÉ — l'accès passera par des URL signées (ADR-0002) ;
- identifiants JAMAIS au dépôt : iac/ les génère dans Vault (kvv2/minio/config),
  le Vault Secrets Operator les matérialise, le chart les lit via existingSecret.
  Le SA du pod est nommé "minio" (pas le "minio-sa" amont) car le module
  app_roles borne l'authentification au SA portant le nom de l'app.

⚠ Le workflow minio.yaml écrit ses triggers EN TOUTES LETTRES : une ancre YAML
dans un trigger Gitea Actions fait taire push ET pull_request en silence (vécu
sur arcodange/kadans, issues 113→117). Les workflows plausible/crowdsec/vault de
ce repo en utilisent encore — à vérifier séparément, c'est probablement
pourquoi ils ne partent qu'à la main.

Vérifié : helm dependency update + helm template (11 ressources rendues, SA et
VaultAuth cohérents) + helm lint ✓.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CoafGWmRVESaWX819USUUA
2026-07-25 16:49:34 +02:00
arcodange 9f0adfe14d use self signed cert
Helm Charts / Detect changed charts (push) Successful in 1m2s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2026-01-02 19:07:46 +01:00
arcodange 02322e9a24 use internal .lab instead of failing duckdns.org
Helm Charts / Detect changed charts (push) Successful in 22s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Failing after 34s
2025-12-31 17:54:36 +01:00
arcodange a8c497a5da try plausible CE for web analytics 2025-12-10 15:00:47 +01:00
arcodange 859057be66 configure postgresql for crowdsec
Helm Charts / Detect changed charts (push) Successful in 16s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-12-03 18:08:53 +01:00
arcodange a1261d6c80 workflow dispatch trigger
Helm Charts / Detect changed charts (push) Successful in 50s
Helm Charts / Library charts tool (push) Has been skipped
Helm Charts / Application charts pgcat (push) Has been skipped
2025-08-08 12:32:44 +02:00
arcodange bbb0bc7d5f configure vault secrets operator 2024-10-30 11:21:48 +01:00
arcodange 3a506543ce apply vault config from CI 2024-10-05 23:58:24 +02:00
arcodange ddb0112696 declare tools (#1)
Reviewed-on: https://gitea.arcodange.duckdns.org/arcodange-org/tools/pulls/1
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2024-09-04 11:00:44 +02:00