infra: supervision Prometheus et Grafana, exporters et tableaux de bord #115

Merged
lenaic merged 2 commits from gabriel/31-supervision-prometheus-grafana into develop 2026-09-03 14:42:56 +00:00
Member

Ce que ça change

Pose la pile de supervision (infra/compose/supervision/) déployée par le rôle app : Prometheus, Grafana sans compte par défaut, node-exporter, cAdvisor et postgres-exporter, tous en écoute sur 127.0.0.1. Deux sources Grafana (Prometheus technique, PostgreSQL métier) et quatre tableaux de bord versionnés. Nouveau rôle Ansible proxy qui aligne le Caddyfile de la forge sur le dépôt et le recharge à chaud, avec le vhost grafana.g2.enervision ; le déploiement continu passe à --tags app,proxy.

Closes #31

Preuve

Vérifié sur l'environnement local complet (infra/compose/supervision/local/, PostgreSQL jetable au schéma de la zone or) :

targets prometheus : prometheus up · node up · cadvisor up · postgres up
datasources        : Prometheus OK · PostgreSQL "Database Connection OK"
tableaux de bord   : socle, hote, conteneurs, postgresql
compte par défaut  : curl -u admin:admin .../api/org -> 401
socle, panneau métier : SELECT count(*) FROM public.mesure -> 1015 (jeu local)
52 panneaux renvoient des données ; les 10 restants (disque `/`, conteneurs)
ne se remplissent que sur l'hôte Linux — limite de Docker Desktop, documentée
dans infra/compose/supervision/local/README.md.

Sur le serveur, il reste à rejouer site.yml --tags app,proxy, recharger Caddy
et joindre la capture des deux sources vertes (mise en service #31).

Relecture

  • Un pair a relu et laissé un commentaire, même court
  • Ses remarques sont traitées, ou une réponse explique pourquoi elles ne le sont pas

Ce qui suit le code

  • docs/runbooks/ mis à jour : supervision.md (neuf), forge.md §5 bis, deploiement.md
  • Une nouvelle variable d'environnement est apparue, elle est dans .env.example (GF_SECURITY_ADMIN_*, DATA_SOURCE_PASS)

Où regarder en priorité

  • Rôle proxy (infra/ansible/roles/proxy/) : le remplacement du Caddyfile se fait EN PLACE (cp, pas de renommage) sinon le montage de fichier du conteneur ne suit pas. Validé dans un conteneur jetable avant rechargement, rescue qui ne touche pas Caddy si la validation échoue.
  • --tags app,proxy dans deploy.yml : le rôle proxy entre dans le chemin du déploiement continu. Il ne touche qu'à un fichier de config et à un caddy reload, jamais au socle.
  • Coffre : vault_grafana_admin_user / vault_grafana_admin_password ajoutés (chiffrés). L'assertion du rôle app exige 14 caractères minimum sur le mot de passe.
  • Le 5e critère de #31 (« servi par Caddy ») dépendait de la pile forge : elle a été versionnée entre-temps (#101), d'où le choix du vhost dans son Caddyfile plutôt qu'un Caddy séparé.
## Ce que ça change Pose la pile de supervision (`infra/compose/supervision/`) déployée par le rôle `app` : Prometheus, Grafana sans compte par défaut, node-exporter, cAdvisor et postgres-exporter, tous en écoute sur `127.0.0.1`. Deux sources Grafana (Prometheus technique, PostgreSQL métier) et quatre tableaux de bord versionnés. Nouveau rôle Ansible `proxy` qui aligne le `Caddyfile` de la forge sur le dépôt et le recharge à chaud, avec le vhost `grafana.g2.enervision` ; le déploiement continu passe à `--tags app,proxy`. Closes #31 ## Preuve Vérifié sur l'environnement local complet (`infra/compose/supervision/local/`, PostgreSQL jetable au schéma de la zone or) : ``` targets prometheus : prometheus up · node up · cadvisor up · postgres up datasources : Prometheus OK · PostgreSQL "Database Connection OK" tableaux de bord : socle, hote, conteneurs, postgresql compte par défaut : curl -u admin:admin .../api/org -> 401 socle, panneau métier : SELECT count(*) FROM public.mesure -> 1015 (jeu local) 52 panneaux renvoient des données ; les 10 restants (disque `/`, conteneurs) ne se remplissent que sur l'hôte Linux — limite de Docker Desktop, documentée dans infra/compose/supervision/local/README.md. ``` Sur le serveur, il reste à rejouer `site.yml --tags app,proxy`, recharger Caddy et joindre la capture des deux sources vertes (mise en service #31). ## Relecture - [ ] Un pair a relu et laissé un commentaire, même court - [ ] Ses remarques sont traitées, ou une réponse explique pourquoi elles ne le sont pas ## Ce qui suit le code - [x] `docs/runbooks/` mis à jour : `supervision.md` (neuf), `forge.md` §5 bis, `deploiement.md` - [x] Une nouvelle variable d'environnement est apparue, elle est dans `.env.example` (`GF_SECURITY_ADMIN_*`, `DATA_SOURCE_PASS`) ## Où regarder en priorité - **Rôle `proxy`** (`infra/ansible/roles/proxy/`) : le remplacement du `Caddyfile` se fait EN PLACE (`cp`, pas de renommage) sinon le montage de fichier du conteneur ne suit pas. Validé dans un conteneur jetable avant rechargement, `rescue` qui ne touche pas Caddy si la validation échoue. - **`--tags app,proxy`** dans `deploy.yml` : le rôle `proxy` entre dans le chemin du déploiement continu. Il ne touche qu'à un fichier de config et à un `caddy reload`, jamais au socle. - **Coffre** : `vault_grafana_admin_user` / `vault_grafana_admin_password` ajoutés (chiffrés). L'assertion du rôle `app` exige 14 caractères minimum sur le mot de passe. - Le 5e critère de #31 (« servi par Caddy ») dépendait de la pile forge : elle a été versionnée entre-temps (#101), d'où le choix du vhost dans son `Caddyfile` plutôt qu'un Caddy séparé.
infra: supervision Prometheus et Grafana, exporters et tableaux de bord
All checks were successful
Intégration / Qualité du code Python (pull_request) Successful in 46s
Intégration / Tests unitaires et couverture (pull_request) Successful in 50s
Intégration / Dépendances du tableau de bord (pull_request) Successful in 14s
Intégration / Images épinglées par version (pull_request) Successful in 4s
Intégration / Tableau de bord (pull_request) Successful in 18s
Intégration / Aucun secret commité (pull_request) Successful in 2s
Intégration / Dépendances Python et inventaire applicatif (pull_request) Successful in 1m29s
Infra Ansible / Playbooks Ansible valides (pull_request) Successful in 1m2s
1b31f7f636
Pose la pile supervision (infra/compose/supervision), déployée par le rôle app :
Prometheus, Grafana sans compte par défaut, node-exporter, cAdvisor et
postgres-exporter, tous en écoute sur 127.0.0.1. Deux sources Grafana
(Prometheus pour la technique, PostgreSQL pour le métier) et quatre tableaux de
bord versionnés : socle, hote, conteneurs, postgresql.

Nouveau rôle Ansible proxy : aligne le Caddyfile de la forge sur le dépôt, le
valide dans un conteneur jetable puis recharge Caddy à chaud. Pose le vhost
grafana.g2.enervision. Le déploiement continu passe à --tags app,proxy.

Environnement local complet sous infra/compose/supervision/local (réseau bridge,
ports publiés, PostgreSQL jetable avec schéma d'exemple) pour travailler les
tableaux de bord hors serveur.

Contrôle CI tests/ci/test-supervision.sh. Ports 9100, 9101 et 9187 ajoutés au
plan d'adressage. Manuel docs/runbooks/supervision.md.

Closes #31
gabriel self-assigned this 2026-09-03 11:39:54 +00:00
gabriel 2026-09-03 11:39:55 +00:00
lenaic left a comment

Relu en entier : le rôle proxy, la composition de supervision, le provisionnement
Grafana, les changements du rôle app, du Caddyfile, de la chaîne et du plan
d'adressage. C'est du bon travail, et le rôle proxy en est le meilleur morceau.

Deux points empêchent la pile de fonctionner, et aucun des deux n'est dans ton code : ils
viennent d'une dérive entre le coffre et le serveur. Je les ai corrigés dans la #114,
qui fusionne avant celle-ci. Tu n'as donc rien à changer, mais tu dois savoir pourquoi.

Ce qui bloquerait au démarrage

1. Le mot de passe du rôle PostgreSQL grafana était refusé par le serveur.

Tes deux consommateurs le lisent : la source de données PostgreSQL EnerVision et
postgres-exporter, via PG_GRAFANA_PASSWORD et DATA_SOURCE_PASS. Les deux auraient
échoué à la connexion — tableau de bord métier vide, exportateur muet, et rien dans la
demande ne l'aurait laissé prévoir.

Vérifié sur le serveur, avec un contre-essai pour ne pas crier au loup : un mot de passe
volontairement faux est bien rejeté, donc le refus était réel et non un artefact de mon
test.

La cause n'est pas chez toi. postgres.env n'est lu qu'à la première initialisation du
volume
: passé ce moment, changer une valeur dans le coffre ne change plus rien côté
serveur, et les deux dérivent sans que rien ne le signale. J'avais déjà trouvé la même
chose pour enervision_prod et enervision_preprod en écrivant la #114 ; grafana en
était exclu, il ne l'est plus.

2. Le rôle grafana n'était pas membre de pg_monitor.

postgres-exporter lit pg_stat_replication, pg_stat_wal et le texte des requêtes de
pg_stat_activity. Sans ce droit il démarre, rend des métriques partielles et journalise
des erreurs. Mesuré avant et après sur le serveur :

avant : requêtes lisibles dans pg_stat_activity —  0 / 23
après : requêtes lisibles dans pg_stat_activity — 23 / 23

Ta preuve annonce « 52 panneaux renvoient des données », mesurée sur l'environnement
local où le rôle a été créé autrement. C'est le genre d'écart qui ne se voit qu'en
confrontant au serveur.

La #114 accorde pg_monitor et réaligne le mot de passe. Le rôle reste en lecture seule
sur les données métier. mlflow est volontairement laissé en dehors du réalignement : il
tourne et lit son mot de passe dans mlflow.env, le réaligner le couperait de sa base.

Ce qui est juste, et que je garderais tel quel

Le rôle proxy. Validation de la configuration candidate dans un conteneur jetable
avant de toucher à celui en service, sauvegarde datée, remplacement en place pour que
l'inode ne change pas — le piège du montage de fichier, que tu documentes — et un bloc de
secours qui nettoie sans avoir rechargé. C'est exactement ce qu'on veut d'un rôle qui
touche à la porte d'entrée de la forge.

Le Caddyfile du dépôt ne diverge pas de celui qui sert. Je les ai comparés ligne à
ligne : le tien est l'actuel plus le vhost Grafana. Rien ne se perd au premier
déploiement, ce qui était ma première inquiétude en voyant un rôle qui écrase la
configuration de Caddy.

L'exposition est bornée par les adresses d'écoute, et elles sont toutes en
127.0.0.1.
J'ai regardé le mode réseau hôte de près, puisque c'est lui qui a coupé le
serveur le 3 septembre. Ici il est justifié — node-exporter et cAdvisor n'ont pas de
sens autrement — et le fichier le dit avec l'avertissement qui va avec. Ma réserve tombe.

Images épinglées par empreinte, secrets jamais dans le dépôt et interpolés à
l'exécution, deleteDatasources pour l'idempotence du provisionnement, et le plan
d'adressage complété des trois ports d'exportateurs.

Et surtout, tests/ci/test-supervision.sh. Tu ne te contentes pas de bien faire, tu
empêches le prochain de mal faire : écoute sur 0.0.0.0, compte par défaut, mot de passe
en clair. C'est ce qui manque le plus souvent à ce genre de pile.

Ce qu'il te reste à faire

Rien dans ton code. Un rebase, et une réponse à la question du bas. Je n'ai pas mis de
demande de changements pour cette raison : les deux correctifs sont dans la #114, pas chez
toi.

Un point de coordination

Nos deux demandes se marchent dessus sur infra/ansible/group_vars/all/vars.yml : on
ajoute chacun une pile à app_stacks. roles/app/tasks/main.yml fusionne tout seul,
tu ajoutes en haut et j'ajoute en bas.

La #114 passe en premier — elle porte les deux correctifs ci-dessus, sans lesquels ta pile
ne démarre pas. Il te restera un rebase de quelques lignes sur vars.yml.

Dernière chose, à confirmer d'un mot : ton vault.yml change entièrement dans le diff,
ce qui est normal pour un fichier chiffré. Peux-tu juste me dire que tu n'y as ajouté
que les deux clés Grafana, sans régénérer les mots de passe PostgreSQL existants ? La
#114 réaligne le serveur sur ces valeurs, donc si l'un d'eux a bougé, il faut le savoir
avant le déploiement et pas après.

Relu en entier : le rôle `proxy`, la composition de supervision, le provisionnement Grafana, les changements du rôle `app`, du `Caddyfile`, de la chaîne et du plan d'adressage. **C'est du bon travail, et le rôle `proxy` en est le meilleur morceau.** Deux points empêchent la pile de fonctionner, et aucun des deux n'est dans ton code : ils viennent d'une dérive entre le coffre et le serveur. Je les ai corrigés dans la **#114**, qui fusionne avant celle-ci. Tu n'as donc rien à changer, mais tu dois savoir pourquoi. ## Ce qui bloquerait au démarrage **1. Le mot de passe du rôle PostgreSQL `grafana` était refusé par le serveur.** Tes deux consommateurs le lisent : la source de données `PostgreSQL EnerVision` et `postgres-exporter`, via `PG_GRAFANA_PASSWORD` et `DATA_SOURCE_PASS`. Les deux auraient échoué à la connexion — tableau de bord métier vide, exportateur muet, et rien dans la demande ne l'aurait laissé prévoir. Vérifié sur le serveur, avec un contre-essai pour ne pas crier au loup : un mot de passe volontairement faux est bien rejeté, donc le refus était réel et non un artefact de mon test. La cause n'est pas chez toi. `postgres.env` n'est lu qu'à la **première initialisation du volume** : passé ce moment, changer une valeur dans le coffre ne change plus rien côté serveur, et les deux dérivent sans que rien ne le signale. J'avais déjà trouvé la même chose pour `enervision_prod` et `enervision_preprod` en écrivant la #114 ; `grafana` en était exclu, il ne l'est plus. **2. Le rôle `grafana` n'était pas membre de `pg_monitor`.** `postgres-exporter` lit `pg_stat_replication`, `pg_stat_wal` et le texte des requêtes de `pg_stat_activity`. Sans ce droit il démarre, rend des métriques partielles et journalise des erreurs. Mesuré avant et après sur le serveur : ``` avant : requêtes lisibles dans pg_stat_activity — 0 / 23 après : requêtes lisibles dans pg_stat_activity — 23 / 23 ``` Ta preuve annonce « 52 panneaux renvoient des données », mesurée sur l'environnement local où le rôle a été créé autrement. C'est le genre d'écart qui ne se voit qu'en confrontant au serveur. La #114 accorde `pg_monitor` et réaligne le mot de passe. Le rôle reste en lecture seule sur les données métier. `mlflow` est volontairement laissé en dehors du réalignement : il tourne et lit son mot de passe dans `mlflow.env`, le réaligner le couperait de sa base. ## Ce qui est juste, et que je garderais tel quel **Le rôle `proxy`.** Validation de la configuration candidate dans un conteneur jetable avant de toucher à celui en service, sauvegarde datée, remplacement **en place** pour que l'inode ne change pas — le piège du montage de fichier, que tu documentes — et un bloc de secours qui nettoie sans avoir rechargé. C'est exactement ce qu'on veut d'un rôle qui touche à la porte d'entrée de la forge. **Le `Caddyfile` du dépôt ne diverge pas de celui qui sert.** Je les ai comparés ligne à ligne : le tien est l'actuel plus le vhost Grafana. Rien ne se perd au premier déploiement, ce qui était ma première inquiétude en voyant un rôle qui écrase la configuration de Caddy. **L'exposition est bornée par les adresses d'écoute, et elles sont toutes en `127.0.0.1`.** J'ai regardé le mode réseau hôte de près, puisque c'est lui qui a coupé le serveur le 3 septembre. Ici il est justifié — `node-exporter` et cAdvisor n'ont pas de sens autrement — et le fichier le dit avec l'avertissement qui va avec. Ma réserve tombe. **Images épinglées par empreinte**, secrets jamais dans le dépôt et interpolés à l'exécution, `deleteDatasources` pour l'idempotence du provisionnement, et le plan d'adressage complété des trois ports d'exportateurs. **Et surtout, `tests/ci/test-supervision.sh`.** Tu ne te contentes pas de bien faire, tu empêches le prochain de mal faire : écoute sur `0.0.0.0`, compte par défaut, mot de passe en clair. C'est ce qui manque le plus souvent à ce genre de pile. ## Ce qu'il te reste à faire Rien dans ton code. Un rebase, et une réponse à la question du bas. Je n'ai pas mis de demande de changements pour cette raison : les deux correctifs sont dans la #114, pas chez toi. ## Un point de coordination Nos deux demandes se marchent dessus sur `infra/ansible/group_vars/all/vars.yml` : on ajoute chacun une pile à `app_stacks`. `roles/app/tasks/main.yml` fusionne tout seul, tu ajoutes en haut et j'ajoute en bas. La #114 passe en premier — elle porte les deux correctifs ci-dessus, sans lesquels ta pile ne démarre pas. Il te restera un rebase de quelques lignes sur `vars.yml`. Dernière chose, à confirmer d'un mot : ton `vault.yml` change entièrement dans le diff, ce qui est normal pour un fichier chiffré. Peux-tu juste me dire que tu n'y as **ajouté** que les deux clés Grafana, sans régénérer les mots de passe PostgreSQL existants ? La #114 réaligne le serveur sur ces valeurs, donc si l'un d'eux a bougé, il faut le savoir avant le déploiement et pas après.
gabriel requested reviews from lenaic and removed review requests for olivier 2026-09-03 13:22:47 +00:00
Merge develop dans gabriel/31-supervision-prometheus-grafana
All checks were successful
Intégration / Qualité du code Python (pull_request) Successful in 1m15s
Intégration / Tests unitaires et couverture (pull_request) Successful in 56s
Intégration / Dépendances du tableau de bord (pull_request) Successful in 15s
Intégration / Images épinglées par version (pull_request) Successful in 3s
Intégration / Tableau de bord (pull_request) Successful in 19s
Intégration / Aucun secret commité (pull_request) Successful in 2s
Intégration / Dépendances Python et inventaire applicatif (pull_request) Successful in 1m28s
Infra Ansible / Playbooks Ansible valides (pull_request) Successful in 56s
12a7f90150
Deux conflits, tous deux dus à la #114 fusionnée entre-temps.

app_stacks : on ajoutait chacun une pile après minio. Les quatre y sont
maintenant, dans l'ordre postgres, minio, mlflow, supervision. La supervision
passe en dernier pour la raison que Gabriel donnait déjà : Grafana teste sa
source « métier » au démarrage, et cette source est PostgreSQL, qui doit donc
être debout et saine — ce que le `wait: true` des piles précédentes garantit.

Elle reçoit `env: true` : son `supervision.env` sert à l'interpolation du
provisionnement Grafana, pas seulement au conteneur.

deploy.yml : la preuve d'après-déploiement couvre désormais les quatre piles au
lieu de deux listes qui s'ignoraient.

roles/app/tasks/main.yml fusionne sans conflit, Gabriel ajoutant en haut et moi
en bas.

Vérifié : yamllint, ansible-lint au profil production, les trois contrôles de
syntaxe, et le banc d'essai du rôle app.
lenaic approved these changes 2026-09-03 14:42:52 +00:00
lenaic merged commit e3282bbb43 into develop 2026-09-03 14:42:56 +00:00
lenaic deleted branch gabriel/31-supervision-prometheus-grafana 2026-09-03 14:42:56 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
g2/enervision!115
No description provided.