fix(infra,ci): le déploiement migre la base, et la doc cesse de dire déployé
`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
This commit is contained in:
@@ -21,6 +21,7 @@ concurrency:
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: [self-hosted, linux, eni-g3]
|
||||
timeout-minutes: 30
|
||||
environment:
|
||||
name: ${{ github.ref_name == 'main' && 'prod' || 'rec' }}
|
||||
url: ${{ github.ref_name == 'main' && 'https://enervision.local' || 'https://rec.enervision.local:8443' }}
|
||||
@@ -50,5 +51,7 @@ jobs:
|
||||
sleep 5
|
||||
done
|
||||
echo "L'API ne répond pas après 3 minutes" >&2
|
||||
cd "/srv/enervision/${ENVIRONNEMENT}" && docker compose ps
|
||||
cd "/srv/enervision/${ENVIRONNEMENT}"
|
||||
docker compose ps
|
||||
docker compose logs --tail=50 backend proxy
|
||||
exit 1
|
||||
|
||||
@@ -124,12 +124,15 @@ docker-build: ## Construit l'image du backend
|
||||
tls-selfsigned: ## Génère le certificat de démonstration. PUBLIC_HOST=..., FORCE=1 pour écraser
|
||||
./scripts/tls-selfsigned.sh $(if $(FORCE),--force,)
|
||||
|
||||
stack-up: ## Démarre la stack complète derrière le reverse proxy (80/443). PUBLIC_HOST=... au besoin
|
||||
# Piège : l'image backend ne migre pas au démarrage, et `/health/ready` ne teste que la connexion
|
||||
# et l'extension. Sans `alembic upgrade head`, la stack démarre verte sur une base sans schéma.
|
||||
stack-up: ## Démarre la stack derrière le reverse proxy, puis migre la base. PUBLIC_HOST=... au besoin
|
||||
@test -f infra/proxy/tls/fullchain.pem \
|
||||
|| { echo "Aucun certificat dans infra/proxy/tls. Lancer d'abord make tls-selfsigned"; exit 1; }
|
||||
@openssl x509 -in infra/proxy/tls/fullchain.pem -noout -checkhost "$(PUBLIC_HOST)" >/dev/null \
|
||||
|| { echo "Le certificat ne couvre pas $(PUBLIC_HOST). Relancer make tls-selfsigned PUBLIC_HOST=$(PUBLIC_HOST) FORCE=1"; exit 1; }
|
||||
$(COMPOSE_PROD) up -d --build
|
||||
$(COMPOSE_PROD) exec -T backend alembic upgrade head
|
||||
|
||||
stack-down: ## Arrête la stack complète en conservant les données
|
||||
$(COMPOSE_PROD) stop
|
||||
|
||||
@@ -89,7 +89,7 @@ collecteur ne vient le lire.
|
||||
| Infra | Docker Compose, Nginx, Terraform, k3s single-node | `infra`, `docker-compose.prod.yml` | `En cours` | Reverse proxy et overlay de déploiement écrits et validés, jamais lancés sur le serveur ([ADR 0007](../adr/0007-terminaison-tls-et-reverse-proxy-nginx.md)). Module d'installation k3s jamais appliqué, aucune ressource Kubernetes déclarée |
|
||||
| Monitoring | Prometheus, Grafana, Alertmanager | `monitoring` | `Cible` | Rien, hors le `/metrics` exposé par l'API |
|
||||
| ETL | Apache Airflow | `etl/airflow` | `En cours` | Webserver + scheduler (LocalExecutor) tournent via docker-compose, base de métadonnées Postgres dédiée. Trois DAGs en sous-processus `uv run` : `ml_train` manuel et `ml_score` `@hourly` pour le pipeline ML (issue #115), `alertes` à `15 * * * *` pour la détection et les recommandations (issue #116, [ADR 0008](../adr/0008-airflow-execute-le-code-du-backend.md)). L'ingestion (issues #15/#16) n'a pas encore de DAG |
|
||||
| CI/CD | GitHub Actions | `.github/workflows` | `Fait` | 6 workflows, 17 jobs : lint, typage, tests avec seuil de couverture bloquant, tests d'intégration sur TimescaleDB réel, audit de dépendances, SAST Bandit, quality gate SonarCloud, intégrité des DAGs Airflow. Déploiement continu vers la VM ENI par `deploy.yml` et un runner auto-hébergé : `dev` en recette, `main` en production après approbation ([ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md)). Détail dans [50-cicd.md](50-cicd.md) |
|
||||
| CI/CD | GitHub Actions | `.github/workflows` | `En cours` | 6 workflows, 18 jobs : lint, typage, tests avec seuil de couverture bloquant, tests d'intégration sur TimescaleDB réel, audit de dépendances, SAST Bandit, quality gate SonarCloud, intégrité des DAGs Airflow. Déploiement continu vers la VM ENI écrit par `deploy.yml`, `dev` en recette et `main` en production après approbation ([ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md)), mais jamais exécuté : la machine n'est pas provisionnée et le runner n'y est pas enregistré. Détail dans [50-cicd.md](50-cicd.md) |
|
||||
|
||||
## Flux bout en bout
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ quel contexte, quelles décisions sont arrêtées, et ce qui manque encore entre
|
||||
|---|---|---|
|
||||
| Docker Compose | Développer et recetter sur le poste | `Fait` |
|
||||
| Docker Compose plus reverse proxy | Déployer sur la machine on-premise | `Fait` |
|
||||
| Deux projets Compose sur la VM ENI, recette et production | Déploiement continu depuis GitHub | `Fait` |
|
||||
| Deux projets Compose sur la VM ENI, recette et production | Déploiement continu depuis GitHub | `En cours` |
|
||||
| k3s single-node | Cible à terme | `En cours` |
|
||||
|
||||
## Poste de développement
|
||||
@@ -172,8 +172,9 @@ Deux conséquences se propagent jusqu'à l'application, et elles ne se devinent
|
||||
|
||||
### Deux environnements sur la même machine
|
||||
|
||||
Statut : `Fait`. Décision et motifs dans l'[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md).
|
||||
La VM `eadl-2025-nantes-g3` porte la recette et la production, chacune dans son clone du dépôt,
|
||||
Statut : `En cours`, la machine n'étant pas encore provisionnée. Décision et motifs dans
|
||||
l'[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md).
|
||||
La VM `eadl-2025-nantes-g3` portera la recette et la production, chacune dans son clone du dépôt,
|
||||
son `.env` et son projet Compose. Le nom de projet préfixe volumes, réseau et conteneurs : rien
|
||||
n'est partagé. `scripts/provision-host.sh` prépare les deux dossiers, génère les secrets et les
|
||||
certificats, et ne démarre rien.
|
||||
|
||||
@@ -6,13 +6,15 @@ vérifié, ce qui bloque, et ce qui ne l'est pas.
|
||||
| Étage | Sert à | Statut |
|
||||
|---|---|---|
|
||||
| Intégration continue | Interdire le merge d'un code qui casse la qualité, les tests ou la sécurité | `Fait` |
|
||||
| Livraison continue | Déployer chaque branche d'intégration sur son environnement de la VM ENI | `Fait` |
|
||||
| Livraison continue | Déployer chaque branche d'intégration sur son environnement de la VM ENI | `En cours` |
|
||||
|
||||
Le **D** de CI/CD existe depuis le 21/09 : `deploy.yml` déploie `dev` en recette et `main` en
|
||||
Le **D** de CI/CD est écrit depuis le 21/09 : `deploy.yml` déploie `dev` en recette et `main` en
|
||||
production sur la VM de l'école, par un runner auto-hébergé (issue #21,
|
||||
[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md)). Sa limite, nommée ici
|
||||
plutôt que découverte en soutenance : les images sont construites sur la machine à chaque
|
||||
déploiement, aucun artefact n'est publié puis promu d'un environnement à l'autre.
|
||||
[ADR 0009](../adr/0009-deux-environnements-compose-sur-la-vm-eni.md)). Il n'a encore rien
|
||||
déployé : la machine n'est pas provisionnée et le runner n'y est pas enregistré. Statut à
|
||||
basculer sur `Fait` au premier déploiement vert. Sa limite, nommée ici plutôt que découverte en
|
||||
soutenance : les images sont construites sur la machine à chaque déploiement, aucun artefact
|
||||
n'est publié puis promu d'un environnement à l'autre.
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
@@ -105,9 +107,12 @@ entrant n'est ouvert.
|
||||
| `push` sur `main` | `prod` | `/srv/enervision/prod` | approbation d'un relecteur dans l'environnement `prod`, branche `main` seule autorisée |
|
||||
|
||||
Le job aligne le clone sur la branche (`fetch`, `checkout`, `reset --hard`), lance
|
||||
`make stack-up`, qui reconstruit les images et redémarre les conteneurs, puis attend jusqu'à trois
|
||||
minutes que `/api/v1/health/ready` réponde derrière le proxy. Un groupe de concurrence par
|
||||
branche, sans annulation, empêche deux déploiements simultanés du même environnement.
|
||||
`make stack-up`, qui reconstruit les images, redémarre les conteneurs puis applique les
|
||||
migrations Alembic dans le conteneur backend, et attend jusqu'à trois minutes que
|
||||
`/api/v1/health/ready` réponde derrière le proxy. Cette sonde ne vérifie que la connexion à la
|
||||
base et la présence de TimescaleDB : sans la migration, le déploiement serait vert sur une base
|
||||
sans schéma, et c'est pourquoi `make stack-up` la porte. Un groupe de concurrence par branche,
|
||||
sans annulation, empêche deux déploiements simultanés du même environnement.
|
||||
|
||||
Le job ne fait pas de `actions/checkout` dans son espace de travail, et c'est voulu : le dossier
|
||||
de l'environnement est stable, hors du runner, parce que `.env`, certificats et volumes doivent
|
||||
@@ -116,9 +121,13 @@ survivre d'un déploiement à l'autre.
|
||||
**Piège à connaître.** Un runner auto-hébergé sur un dépôt public exécute ce qu'un workflow lui
|
||||
envoie, et une PR de fork peut réécrire un workflow. Trois parades, et les trois sont
|
||||
nécessaires : `deploy.yml` ne se déclenche jamais sur `pull_request` ; le runner tourne sous un
|
||||
utilisateur dédié membre du groupe `docker`, jamais root ; le dépôt exige une approbation pour
|
||||
les workflows des PR externes (Settings, Actions, « Require approval for all outside
|
||||
collaborators »). Les workflows de CI restent sur `ubuntu-latest`.
|
||||
utilisateur dédié membre du groupe `docker`, jamais root ; le dépôt doit exiger une approbation
|
||||
pour les workflows des PR externes (Settings, Actions, « Require approval for all outside
|
||||
collaborators »), ce qui reste à activer. Les workflows de CI restent sur `ubuntu-latest`.
|
||||
|
||||
Cet utilisateur dédié doit posséder `/srv/enervision` : sinon git refuse les deux clones pour
|
||||
propriété douteuse et le `.env` en `600` lui échappe. `PROPRIETAIRE=<utilisateur du runner>`
|
||||
passé à `scripts/provision-host.sh` fixe ce propriétaire.
|
||||
|
||||
La machine se prépare avec `scripts/provision-host.sh`, qui vérifie Docker et Compose 2.24.4 ou
|
||||
plus, clone les deux branches, génère les secrets de chaque `.env` et les certificats
|
||||
|
||||
@@ -90,7 +90,12 @@ fi
|
||||
|
||||
cat <<FIN
|
||||
|
||||
Démarrage, dans chaque dossier : make stack-up
|
||||
Le runner GitHub Actions (label eni-g3) refera la même chose à chaque push sur dev et main.
|
||||
Démarrage, dans chaque dossier : make stack-up, qui applique aussi les migrations.
|
||||
Premier administrateur, stack démarrée, dans chaque dossier :
|
||||
docker compose -f docker-compose.yml -f docker-compose.prod.yml exec backend \\
|
||||
python -m app.cli create-admin --email <adresse>
|
||||
Le runner GitHub Actions (label eni-g3) rejouera le déploiement à chaque push sur dev et main.
|
||||
L'installer sous le propriétaire de $RACINE, sinon git refuse ces dépôts et le .env en 600 lui
|
||||
échappe : relancer au besoin ce script avec PROPRIETAIRE=<utilisateur du runner>.
|
||||
Depuis un poste : ajouter « $ADRESSE enervision.local rec.enervision.local » à /etc/hosts.
|
||||
FIN
|
||||
|
||||
Reference in New Issue
Block a user