Le seul Terraform du dépôt installait un cluster k3s que rien ne consomme, et sa racine ne passait même pas `terraform init` : depuis Terraform 1.x, un provisioner `destroy` impose que tout le bloc `connection` ne lise que `self`, et celui du module k3s lisait `var.*`. Il est corrigé en batissant la connexion sur `triggers`, où ne figurent que l'adresse, le port, l'utilisateur et le chemin de la clé : jamais la clé ni un mot de passe. `environments/vm-eni` provisionne la machine qui porte la recette et la production : Docker et le plugin Compose, `scripts/provision-host.sh`, puis l'enregistrement du runner. Rien n'y construit d'image ni ne lance de conteneur, et un `apply` n'interrompt pas la stack qui tourne. Le déploiement continu ne bouge pas : `deploy.yml` reste le seul chemin de livraison. `environments/dev` devient `k3s-cible`, parce qu'il provisionnait un cluster et pas un environnement applicatif, et que `rec` et `prod` vivent sur la même machine. `environments/prod`, dossier vide, disparaît. `infra.yml` formate et valide chaque racine à chaque push : c'est l'absence d'un tel job qui a laissé ce Terraform cassé sans que rien ne le dise. La boucle parcourt `environments/*`, une racine ajoutée est couverte sans y toucher. ADR 0010 pour la frontière entre provisionnement et livraison, et la doc d'architecture alignée dessus.
83 lines
5.0 KiB
Markdown
83 lines
5.0 KiB
Markdown
# 0009 - Deux environnements sur la VM ENI, un projet Compose chacun, déployés par un runner auto-hébergé
|
|
|
|
- Statut : accepté
|
|
- Date : 2026-09-21
|
|
|
|
## Contexte
|
|
|
|
La grille note EC03 à EC06 sur ce qui est déployé et fonctionnel au J10. Au 21/09, rien ne
|
|
l'est : la CI s'arrête au merge (issue #21), la topologie Compose avec reverse proxy
|
|
([ADR 0007](0007-terminaison-tls-et-reverse-proxy-nginx.md)) n'a jamais quitté le poste, et le
|
|
module Terraform k3s n'a jamais été appliqué. L'école met à disposition une seule VM,
|
|
`eadl-2025-nantes-g3`, sur une adresse privée que les runners hébergés par GitHub ne joignent
|
|
pas, sans DNS public.
|
|
|
|
Il faut deux environnements, recette et production, parce que la stratégie de branches en a
|
|
déjà deux, `dev` et `main`, et qu'un déploiement direct en production à chaque merge sur `dev`
|
|
n'est pas défendable.
|
|
|
|
La branche `feat/deploy` tentait de déployer par provisioners Terraform : nginx système et copie
|
|
du build Angular. La revue postée sur #21 relève huit points bloquants, dont des racines `rec`
|
|
et `prod` qui ne passent pas `terraform validate`.
|
|
|
|
## Décision
|
|
|
|
**Un projet Docker Compose par environnement, sur la même machine.** Deux clones du dépôt,
|
|
`/srv/enervision/rec` sur `dev` et `/srv/enervision/prod` sur `main`, chacun avec son `.env` et
|
|
son `COMPOSE_PROJECT_NAME`. Le nom de projet préfixe volumes, réseau et conteneurs : les deux
|
|
stacks ne partagent rien.
|
|
|
|
**Les ports du proxy et l'origine publique deviennent des variables** de
|
|
`docker-compose.prod.yml`. La production garde 80 et 443. La recette publie 8443 et ramène sa
|
|
redirection HTTP sur la boucle locale, faute de quoi elle renverrait vers la production. Base,
|
|
Mailpit et Airflow restent sur `127.0.0.1`, décalés d'un port.
|
|
|
|
**Deux noms d'hôte**, `enervision.local` et `rec.enervision.local`, sur la même IP. Le cookie de
|
|
rafraîchissement est posé par hôte, pas par port : un seul nom ferait se déconnecter la
|
|
production à chaque connexion en recette.
|
|
|
|
**Un runner GitHub Actions auto-hébergé sur la VM** exécute `deploy.yml` : un `push` sur `dev`
|
|
déploie la recette, un `push` sur `main` déploie la production après approbation dans
|
|
l'environnement GitHub `prod`. Le job aligne le clone sur la branche puis lance `make stack-up`.
|
|
Les images sont construites sur la machine.
|
|
|
|
**Les secrets vivent dans le `.env` de chaque dossier**, générés sur la machine par
|
|
`scripts/provision-host.sh`, jamais dans git ni dans GitHub. Le runner n'a besoin d'aucun
|
|
secret.
|
|
|
|
## Alternatives écartées
|
|
|
|
- **k3s avec un namespace par environnement** : le cluster serait vide, sans manifeste, sans
|
|
registre, sans stockage persistant. C'est la cible de `10-infra.md`, pas celle de la semaine.
|
|
- **Provisioners Terraform de `feat/deploy`** : voir la revue sur #21. Terraform reste l'outil
|
|
de provisionnement de la machine, pas de livraison applicative.
|
|
- **Deux machines**, VM Proxmox et VM Azure ENI : une deuxième infrastructure à justifier devant
|
|
le jury et à provisionner, pour un bénéfice nul sur la grille.
|
|
- **Un seul proxy frontal routant par nom d'hôte vers les deux stacks** : des URL sans port,
|
|
mais le proxy devrait joindre deux réseaux Compose où les services portent les mêmes noms.
|
|
La complexité dépasse le gain.
|
|
- **Images publiées sur GHCR et déployées par digest** : la bonne pratique, remise à plus tard.
|
|
Un registre à authentifier sur la machine, alors que le runner y construit déjà.
|
|
|
|
## Conséquences
|
|
|
|
- Deux TimescaleDB sur une machine de 8 Go : sans réglage, chacune se réserverait 25 % de la
|
|
RAM au premier démarrage. L'overlay fixe `TS_TUNE_MEMORY` à 2 Go et `TS_TUNE_NUM_CPUS` à 2 par
|
|
base. Airflow 3 n'a rien à régler de ce côté : son api-server lance un seul worker par défaut,
|
|
là où le webserver d'Airflow 2 en lançait quatre. La montée à 32 Go prévue par les consignes
|
|
est à demander.
|
|
- Un runner auto-hébergé sur un dépôt public exécute le code qu'on lui envoie. `deploy.yml` ne
|
|
se déclenche jamais sur `pull_request`, le runner tourne sous un utilisateur dédié, et le
|
|
dépôt doit exiger une approbation pour les workflows des PR externes.
|
|
- Les deux environnements construisent leurs images séparément à partir du même commit : ce qui
|
|
tourne en production a été construit deux fois, pas promu. Le passage à GHCR lèvera cette
|
|
limite.
|
|
- Le `make stack-up` du runner reconstruit l'image Airflow, qui copie `ml/` et `apps/backend/`,
|
|
à chaque push : plusieurs minutes par déploiement, acceptable pour la cadence du projet.
|
|
- `environments/prod` de Terraform reste vide. Le provisionnement de la machine est porté par
|
|
`scripts/provision-host.sh`, que Terraform pourra appeler par `remote-exec` le jour où une
|
|
racine visant la VM existera. Cette racine existe depuis l'[ADR 0010](0010-terraform-provisionne-github-actions-deploie.md),
|
|
sous le nom `environments/vm-eni`, et `environments/prod` a disparu avec elle.
|
|
- L'image frontend quitte `dhi.io/nginx`, registre authentifié dont personne n'a l'accès, pour
|
|
`nginx:1.28-alpine`, la même image que le proxy. Elle n'avait jamais été construite.
|