docs: réaligne la documentation sur l'état livré au gel

Trois environnements et un frontal SNI au lieu de deux, certificats Let's
Encrypt par DNS-01, sept DAGs, index des ADR complété jusqu'à 0020. Les
exemples de l'ETL passent en bash et n'utilisent plus l'option --limit,
retirée. L'adresse de la machine est masquée dans l'arbre, les ADR 0009 et
0014 portent une note datée sur l'approbation de la production.
This commit is contained in:
Johan LEROY
2026-09-24 15:55:08 +02:00
parent 9f343e9f42
commit 9ee0de9d55
25 changed files with 315 additions and 212 deletions
+6 -6
View File
@@ -13,7 +13,7 @@ contraintes non négociables cadrent le choix, discutées dans l'issue #89 :
1. **EC06** (grille de notation individuelle) exige un modèle **entraîné, versionné avec
MLflow**, exposé via un endpoint fonctionnel, avec **surveillance du drift** en production.
2. **Aucun GPU dédié** : l'infra tourne on-premise sur une VM à 4 CPU / 8 Gio RAM (ou
`Standard_B2s`/`B2ms` côté Azure, 2 vCPU max) — Azure Machine Learning est de toute façon
`Standard_B2s`/`B2ms` côté Azure, 2 vCPU max) ; Azure Machine Learning est de toute façon
bloqué par la politique Azure du projet.
3. **Délai serré** : le jalon J3 arrive à échéance le lendemain de la décision, J4 concentre déjà
26 issues sur 4 jours. Un modèle long à mettre en œuvre retarde la chaîne complète (service de
@@ -32,7 +32,7 @@ déjà dérivées.
| Régresseurs exogènes | Oui, mais doivent être connus dans le futur au moment de la prédiction | Oui, via lags/moyennes glissantes sur le passé | Oui, natif | Difficile en multivarié | Aucun support | Contexte de prompt seulement, non appris |
| Coût de calcul (VM sans GPU) | Faible | Faible | Élevé (deep learning) | Faible | Faible | Élevé à prohibitif |
| Versionnable MLflow | Oui, nativement | Oui, nativement | Pas de support direct | Oui, générique | Pas de support direct | Rien à versionner (pas un modèle entraîné) |
| Granularité | Un modèle par site (ou par site × métrique) | Un seul modèle global sur tous les sites | Un par site | Un par site | Un par site | — |
| Granularité | Un modèle par site (ou par site × métrique) | Un seul modèle global sur tous les sites | Un par site | Un par site | Un par site | - |
| Effort avant l'échéance | Faible | Moyen (feature engineering) | Élevé | Moyen à élevé | Faible en soi | Élevé, ou factice |
## Décision
@@ -40,7 +40,7 @@ déjà dérivées.
**LightGBM, un seul modèle global** couvrant tous les sites, plutôt qu'un modèle par site
(Prophet) ou par famille de site. Cible : `consumption_kwh`, avec `period_minutes` comme feature
d'entrée plutôt que comme étape d'agrégation post-prédiction. Suivi et versioning via **MLflow**
(tracking + registre de modèles), sur le magasin local par défaut dans un premier temps —
(tracking + registre de modèles), sur le magasin local par défaut dans un premier temps ;
l'hébergement sur l'infra k3s reste une question ouverte, non bloquante pour démarrer.
Raisons retenues, au-delà du tableau ci-dessus :
@@ -53,7 +53,7 @@ Raisons retenues, au-delà du tableau ci-dessus :
`humidity_percent` et `solar_irradiance_wm2` sont des mesures passées, pas des prévisions, et
aucune source de prévision météo n'existe dans le projet. LightGBM s'en sort avec des features
de lag/moyenne glissante calculées sur l'historique déjà présent dans `reading`, cf.
`ml/enervision_ml/features.py` — un choix qui vaut aussi bien à l'entraînement qu'au futur
`ml/enervision_ml/features.py`, un choix qui vaut aussi bien à l'entraînement qu'au futur
scoring.
- **Apprentissage direct sur `consumption_kwh`** avec `period_minutes` en feature, sans étape
d'agrégation intermédiaire que la sortie continue de Prophet aurait demandée.
@@ -92,9 +92,9 @@ ValentinDeFaria), actée en réunion d'équipe du 2026-09-17 et validée par l'e
- **SARIMA** : ne gère pas nativement plusieurs régresseurs exogènes ; réglage (p,d,q,P,D,Q) plus
long que le délai disponible.
- **NeuralProphet** : fait tout ce que fait Prophet et apprend en plus des motifs autorégressifs,
mais coûte plus cher en calcul (pas de GPU disponible) et n'a pas d'outil MLflow direct — piste
mais coûte plus cher en calcul (pas de GPU disponible) et n'a pas d'outil MLflow direct : piste
d'évolution possible, non engageante à ce stade.
- **Holt-Winters** : écarté d'entrée, pas seulement différé — aucun support de régresseurs
- **Holt-Winters** : écarté d'entrée, pas seulement différé : aucun support de régresseurs
exogènes, alors que la météo et l'irradiance sont nécessaires ici.
- **CatBoost** : même famille que LightGBM, gère nativement les colonnes catégorielles (comme
`site_type`) sans encodage manuel. Non rejeté, différé : candidat à comparer si LightGBM
@@ -2,6 +2,8 @@
- Statut : accepté
- Date : 2026-09-21
- Complété par : [ADR 0017](0017-environnement-dev-a-la-demande.md), troisième environnement `dev`
- Note du 24/09 : l'approbation annoncée avant la production n'a jamais été activée. L'environnement GitHub `prod` n'accepte que `main`, sans relecteur requis.
## Contexte
@@ -1,7 +1,7 @@
# EnerVision · procédure de déploiement (22/09/2026)
Terraform provisionne la machine, GitHub Actions déploie (ADR 0010). Deux environnements Compose
sur la VM ENI `10.101.200.37` : `rec` sur la branche `dev`, `prod` sur `main` (ADR 0009).
sur la VM ENI `<IP-VM-G3>` : `rec` sur la branche `dev`, `prod` sur `main` (ADR 0009).
| | recette | production |
|---|---|---|
@@ -13,7 +13,7 @@ sur la VM ENI `10.101.200.37` : `rec` sur la branche `dev`, `prod` sur `main` (A
## 0. Avant toute commande
1. **Clé SSH déposée** sur la VM : `ssh-copy-id -i ~/.ssh/id_ed25519.pub root@10.101.200.37`.
1. **Clé SSH déposée** sur la VM : `ssh-copy-id -i ~/.ssh/id_ed25519.pub root@<IP-VM-G3>`.
Terraform ne gère **pas** l'authentification par mot de passe (elle finirait dans le state).
2. **L'utilisateur propriétaire existe déjà** sur la VM (ex. `enervision`) : il possède
`/srv/enervision` et fait tourner le runner. Terraform échoue tôt s'il manque, il ne le crée pas.
@@ -42,7 +42,7 @@ runner_version = "2.330.0" # épingler depuis github.com/actions/runner/rel
runner_token = "..." # jeton d'1 h, à retirer du fichier après l'apply
```
Défauts utiles : `ssh_host = "10.101.200.37"`, `ssh_user = "root"`,
Défauts utiles : `ssh_host = "<IP-VM-G3>"`, `ssh_user = "root"`,
`ssh_private_key_path = "~/.ssh/id_ed25519"`, `racine = "/srv/enervision"`,
`runner_labels = "eni-g3"` (ciblé par `deploy.yml`), `runner_dossier = "/opt/actions-runner"`.
@@ -134,7 +134,7 @@ curl -k https://localhost/api/v1/health/ready # production, sur la VM
Depuis un poste, ajouter à `/etc/hosts` :
```
10.101.200.37 enervision.local rec.enervision.local
<IP-VM-G3> enervision.local rec.enervision.local
```
Les deux noms sont obligatoires : le cookie `__Secure-ev_refresh` est posé par hôte et non par
@@ -1,7 +1,7 @@
# EnerVision · Recette et production sur la VM ENI, aujourd'hui
État au lundi 21 septembre 2026, 15h. Cible : deux environnements qui tournent sur la VM
`eadl-2025-nantes-g3` (`10.101.200.37`) avant vendredi 25/09 9h, déployés automatiquement depuis
`eadl-2025-nantes-g3` (`<IP-VM-G3>`) avant vendredi 25/09 9h, déployés automatiquement depuis
GitHub. Ce document donne la solution retenue, ce qu'elle change dans le dépôt, et le déroulé de
l'après-midi avec qui fait quoi.
@@ -37,7 +37,7 @@ prod à chaque connexion sur la recette.
- **Un projet Compose isole tout.** Volumes, réseau, noms de conteneurs sont préfixés par le nom
du projet. Casser la recette ne touche pas la prod, ce qui est la raison d'être d'une recette.
- **Le runner sur la VM est la seule façon d'atteindre une IP privée d'école depuis GitHub.** Les
runners hébergés par GitHub ne voient pas `10.101.200.37`. Le runner se connecte en sortie
runners hébergés par GitHub ne voient pas `<IP-VM-G3>`. Le runner se connecte en sortie
vers GitHub, aucun port entrant n'est nécessaire. C'était le choix 16 du dossier EC01 : il
redevient tenu.
- **La promotion existe déjà dans la stratégie de branches** : `dev` puis `main` par PR. Le
@@ -71,9 +71,9 @@ Ce qui ne change pas : `docker-compose.yml`, la configuration Nginx, `infra/terr
| # | Qui | Quoi | Durée |
|---|---|---|---|
| 1 | **ineszang** (seule admin du dépôt) | Environnement `prod` : branche autorisée `main`, un relecteur requis. Environnement `rec` : branche `dev`. Settings > Actions : « Require approval for all outside collaborators ». Générer le jeton d'enregistrement du runner (Settings > Actions > Runners > New self-hosted runner, Linux x64) et le transmettre à Johan | 10 min |
| 2 | **Johan** | Déposer sa clé sur la VM : `ssh-copy-id -i ~/.ssh/id_ed25519.pub root@10.101.200.37`, mot de passe du compte administrateur local des postes de l'école | 2 min |
| 2 | **Johan** | Déposer sa clé sur la VM : `ssh-copy-id -i ~/.ssh/id_ed25519.pub root@<IP-VM-G3>`, mot de passe du compte administrateur local des postes de l'école | 2 min |
| 3 | Johan + Claude | **Fait à 15h** : branche locale `feat/deploy-rec-prod` avec tous les changements du §3, image frontend reconstruite avec succès, fusion Compose vérifiée pour les deux environnements. Reste : commit, push, PR vers `dev` | fait |
| 4 | Claude, par SSH | `scripts/provision-host.sh` sur la VM. Écrire les deux `.env` (secrets générés sur la VM, jamais dans git). Certificats : `PUBLIC_HOST=rec.enervision.local PUBLIC_IP=10.101.200.37 make tls-selfsigned` dans `rec`, idem avec `enervision.local` dans `prod`. Puis `make stack-up` dans chaque dossier | 20 min plus la construction des images |
| 4 | Claude, par SSH | `scripts/provision-host.sh` sur la VM. Écrire les deux `.env` (secrets générés sur la VM, jamais dans git). Certificats : `PUBLIC_HOST=rec.enervision.local PUBLIC_IP=<IP-VM-G3> make tls-selfsigned` dans `rec`, idem avec `enervision.local` dans `prod`. Puis `make stack-up` dans chaque dossier | 20 min plus la construction des images |
| 5 | Johan, sur la VM | Installer le runner sous un utilisateur non-root membre du groupe `docker`, label `eni-g3`, en service systemd (`./config.sh --unattended --labels eni-g3`, `sudo ./svc.sh install && sudo ./svc.sh start`) | 10 min |
| 6 | Équipe | Merger la PR dans `dev` : la recette se redéploie seule. Ouvrir la PR `dev` vers `main` : la prod se déploie après approbation dans l'onglet Environments | 15 min |
| 7 | Tous | Vérifier depuis un poste de l'équipe, `/etc/hosts` renseigné : connexion, tableau de bord, Airflow par tunnel SSH | 15 min |
@@ -2,6 +2,7 @@
- Statut : accepté
- Date : 2026-09-23
- Note du 24/09 : au gel, les règles de branche ne sont pas posées : `prod` n'accepte que `main` mais sans relecteur, `rec` et `dev` n'ont aucune règle, aucune branche n'est protégée. L'approbation des workflows externes n'est pas lisible avec les droits d'un membre.
- Complète : [0009](0009-deux-environnements-compose-sur-la-vm-eni.md), qui reste en vigueur
## Contexte
@@ -12,7 +12,7 @@ Chaque poste devait éditer son `/etc/hosts` et accepter trois avertissements du
rien de présentable à un jury, et rien d'utilisable par quelqu'un qui n'a pas la main sur son
poste.
Contraintes : la VM n'a qu'une IP privée, `10.101.200.37`, que ni Internet ni Let's Encrypt ne
Contraintes : la VM n'a qu'une IP privée, `<IP-VM-G3>`, que ni Internet ni Let's Encrypt ne
joignent, et le réseau de l'école ne doit pas être touché. Vérifications faites le 23/09 : les
résolveurs de l'école rendent bien une adresse privée pour un nom public, la VM sort en HTTPS
vers Let's Encrypt et vers l'API de dynv6, mais le filtrage de l'école bloque duckdns.org, site