deSEC n'ouvre plus de nouveaux domaines dedyn.io, et duckdns.org est
filtré par l'école. dynv6 répond depuis les postes et depuis la VM.
- Zone enervision-g3.dynv6.net ; provision-host.sh pointe la zone, rec
et dev vers la VM par l'API dynv6 (bloc Python, idempotent).
- make tls-dns01 remplace tls-desec : DNS01_API et DNS01_JETON_VAR
nomment le greffon acme.sh, le jeton vit dans ../dns.token quel que
soit le fournisseur. Un domaine acheté ne demandera que ces variables.
- deploy.yml ne demande un certificat qu'à un .env qui ne porte plus de
nom en .local.
- ADR 0018 renommé noms-publics : deSEC et DuckDNS en alternatives.
Le filtrage du réseau de l'école bloque duckdns.org, site et API, depuis
les postes comme depuis la VM : sans API, pas de défi DNS-01. deSEC
(dedyn.io) répond depuis les deux.
- Domaine enervision-g3.dedyn.io ; provision-host.sh publie par l'API
deSEC l'enregistrement du domaine et son joker vers la VM.
- make tls-desec remplace tls-duckdns. acme.sh recopie le jeton dans
acme/account.conf : le dossier est retiré aux autres comptes.
- deploy.yml ne demande un certificat qu'à un .env déjà réaligné sur
le domaine deSEC, pour ne pas faire échouer un déploiement en cours
de migration.
Les trois environnements passent sur enervision-g3.duckdns.org, rec. et
dev. : noms publics qui visent l'IP privée de la VM, donc résolus sans
/etc/hosts sur le réseau de l'école et injoignables ailleurs (ADR 0018).
- infra/front : nginx sur le réseau de l'hôte, seul exposé en 80 et 443.
Aiguille par SNI vers la stack visée sans déchiffrer le TLS, et lui
transmet l'IP du client en PROXY protocol.
- Proxy de stack : écouteur 4443 en PROXY protocol, real_ip_header ;
sans lui, limit_req et get_client_ip() compteraient tous les postes
comme un seul. PROXY_FRONT_PORT le publie sur 127.0.0.1.
- make tls-duckdns : Let's Encrypt par défi DNS-01 via l'API DuckDNS
(acme.sh 3.1.6), rejouable, rejoué à chaque déploiement et chaque nuit.
- provision-host.sh fait foi pour l'adressage et les secrets : un .env
existant garde ses secrets, reçoit ceux qui manquent (supervision) et
voit hôte et ports réalignés. Planifie le renouvellement des certificats.
- deploy.yml : nouvelles URL, sonde prod sur 10443, front-up en prod.
- Terraform : variable domaine. CI : validation du frontal.
Rapatrie l'environnement dev à la demande (#151) et l'en-tête CORP (#149).
- deploy.yml : garde le routage de #151 (main vers prod, dev vers rec, toute autre branche vers
dev) et l'appel par ci.yml après « CI ok ». Le groupe concurrency par environnement cède la
place au flock sur le dossier, qui sérialise aussi deux branches lancées dans dev. La garde
anti-recul ne joue que sur la même branche : dans dev, une autre branche que celle en place
est toujours déployée.
- provision-host.sh : le dossier dev reçoit aussi les clés de supervision, profil inactif,
ports 3003, 9092 et 9095.
- 10-infra.md, 50-cicd.md et ADR 0017 : trois environnements, supervision et verrou flock.
Troisième projet Compose sur la VM ENI, /srv/enervision/dev, alimenté par
workflow_dispatch de n'importe quelle branche autre que dev et main
(https://dev.enervision.local:9443). La recette suit toujours dev, la
production main.
- deploy.yml : routage main -> prod, dev -> rec, autre -> dev ; groupe de
concurrence par environnement et non plus par branche.
- provision-host.sh : prépare le dossier dev (ports 9443, 5435, 8027, 8084) ;
passe safe.directory à git, faute de quoi un second passage en root, celui
de terraform apply, échoue sur les clones déjà remis au runner.
- ADR 0017, 10-infra.md, 50-cicd.md, infra/README.md à jour.
L'API exposait /metrics, mais aucun collecteur ne le lisait : monitoring/ ne contenait que des
.gitkeep.
Sous le profil Compose `monitoring` : prometheus, alertmanager, grafana, postgres-exporter,
node-exporter et cadvisor. Tous ont un mem_limit, pour environ 700 Mo au total sur la VM de 8 Go,
et leurs interfaces n'écoutent que sur 127.0.0.1. Le profil est actif en prod via
COMPOSE_PROFILES, donc à chaque déploiement, et se lance à la demande ailleurs
(make monitoring-up).
- Neuf règles d'alerte (API, base, hôte, cibles). Chacune a un cas dans les tests joués par
`promtool test rules`, en CI comme par make monitoring-check.
- Alertmanager route les alertes par courriel vers Mailpit ; un critical masque le warning de la
même cible.
- Grafana est provisionné : sources Prometheus et TimescaleDB, et trois tableaux de bord (API,
données et dérive du modèle, infrastructure).
- Le rôle PostgreSQL `supervision` est en lecture seule sur les seules tables métier
(db/roles/supervision.sql), posé par make db-ensure-supervision et par stack-up quand le
profil est actif.
- Le jeton de /metrics passe à Prometheus en secret Compose (APP_METRICS_TOKEN) ;
provision-host.sh génère ce secret et les deux autres.
Backend :
- un APP_METRICS_TOKEN vide vaut absent ;
- les sondes de santé ne comptent plus dans les métriques ;
- seaux de latence fins autour de 500 ms ;
- un registre Prometheus par application, sans quoi toute application créée après la première
(dans les tests) ne mesurait rien.
Réf : #26
La migration Airflow 3 est arrivée sur `dev` après l'écriture du chemin de
déploiement, qui en a gardé quatre traces fausses, invisibles en CI puisque
aucun job ne joue ce chemin.
`provision-host.sh` substituait `AIRFLOW_WEBSERVER_SECRET_KEY`, clé disparue.
`AIRFLOW_API_SECRET_KEY` et `AIRFLOW_JWT_SECRET` restaient donc à `change_me`
dans le `.env` posé sur la machine, et le `:?` d'`airflow-init` ne voit pas
une valeur d'exemple : la stack aurait démarré avec un secret de session et un
secret JWT prévisibles. Le `.env` est maintenant écrit après contrôle, et le
script refuse de le poser s'il reste un `change_me` hors `APP_MOCK_API_*`.
`make services-up` démarrait `airflow-webserver`, service supprimé par la
migration ; seul `airflow-up` avait été aligné.
L'overlay posait `AIRFLOW__WEBSERVER__WORKERS`, sans effet en Airflow 3 où la
section est `[api]`. Le réglage disparaît plutôt que d'être renommé : le défaut
y vaut un worker, moins que les deux qu'on visait.
Le diagnostic d'échec de `deploy.yml` lisait les journaux sans l'overlay, donc
sans service `proxy` : il échouait avant d'imprimer quoi que ce soit.
Le DAG `historical_import` arrivé par #138 lit `./data/raw`, monté en lecture seule dans
le scheduler. Le dossier est vide dans un clone : sans dépôt manuel des fichiers, le DAG
n'a rien à charger sur la VM.
`make stack-up` enchaîne `alembic upgrade head` dans le conteneur backend. Rien ne
migrait la base sur le chemin de déploiement, et `/api/v1/health/ready`, qui ne teste
que la connexion et l'extension TimescaleDB, aurait laissé passer un déploiement vert
sur une base sans schéma applicatif.
deploy.yml borne le job à 30 minutes et sort les journaux du backend et du proxy quand
la sonde échoue. provision-host.sh rappelle la création du premier administrateur, et
la propriété de /srv/enervision sans laquelle le runner ne peut ni manipuler les clones
ni lire un `.env` en 600.
Les statuts de livraison continue repassent à `En cours` : le code est écrit, la machine
n'est pas provisionnée, le runner n'est pas enregistré, rien n'a été déployé. À basculer
sur `Fait` au premier déploiement vert. Décompte des jobs corrigé, 18 et non 17.
Refs #21, #22
Un projet Compose par environnement sur la même machine : ports du proxy et origine
publique en variables dans docker-compose.prod.yml, réglage mémoire des deux bases
TimescaleDB et du webserver Airflow. Le workflow deploy.yml déploie dev en recette et
main en production depuis un runner installé sur la VM, jamais sur pull_request.
scripts/provision-host.sh prépare les deux dossiers, secrets et certificats compris,
sans rien démarrer.
L'image frontend quitte dhi.io/nginx, registre authentifié dont personne n'a l'accès,
pour nginx:1.28-alpine : elle n'avait jamais été construite.
ADR 0009, vues infra et CI/CD, README et .env.example mis à jour.
Refs #21, #22