From be6be4294771563f6eea817f36e27a921d04e887 Mon Sep 17 00:00:00 2001 From: Johan LEROY Date: Tue, 22 Sep 2026 11:17:02 +0200 Subject: [PATCH] =?UTF-8?q?fix(infra,ci):=20aligne=20le=20provisionnement?= =?UTF-8?q?=20et=20le=20d=C3=A9ploiement=20sur=20Airflow=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .env.example | 4 ++-- .github/workflows/deploy.yml | 5 +++-- Makefile | 2 +- README.md | 5 +++-- docker-compose.prod.yml | 2 -- ...eux-environnements-compose-sur-la-vm-eni.md | 5 +++-- scripts/provision-host.sh | 18 ++++++++++++++---- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.env.example b/.env.example index b6f56aa..3125b73 100644 --- a/.env.example +++ b/.env.example @@ -70,7 +70,7 @@ PUBLIC_ORIGIN= PROXY_HTTP_PORT= PROXY_HTTPS_PORT= # Réglages mémoire de la stack déployée. Sans eux, timescaledb-tune réserve 25 % de la RAM de la -# machine à chaque base au premier démarrage, et le webserver Airflow lance 4 workers gunicorn. +# machine à chaque base au premier démarrage. L'api-server Airflow 3 n'a rien à régler ici : son +# nombre de workers vaut 1 par défaut, contre 4 pour le webserver d'Airflow 2. TS_TUNE_MEMORY=2GB TS_TUNE_NUM_CPUS=2 -AIRFLOW_WEBSERVER_WORKERS=2 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4055e9c..411e164 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,6 +52,7 @@ jobs: done echo "L'API ne répond pas après 3 minutes" >&2 cd "/srv/enervision/${ENVIRONNEMENT}" - docker compose ps - docker compose logs --tail=50 backend proxy + compose="docker compose -f docker-compose.yml -f docker-compose.prod.yml" + $compose ps + $compose logs --tail=50 backend proxy exit 1 diff --git a/Makefile b/Makefile index b3d3c7b..c749f76 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ services-up: ## Démarre les services conteneurisés dont `make dev` dépend (ba docker compose up -d db mailpit @$(MAKE) --no-print-directory db-wait @$(MAKE) --no-print-directory db-ensure-airflow - docker compose up -d airflow-init airflow-webserver airflow-scheduler + docker compose up -d airflow-init airflow-apiserver airflow-scheduler airflow-dag-processor dev-backend: ## Lance l'API seule en rechargement à chaud @echo "backend -> http://localhost:8000 (docs sur /docs)" diff --git a/README.md b/README.md index 1ce516e..daa08f4 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,9 @@ et frontend en rechargement a chaud sur le poste. | Mailpit | | Le `.env` doit porter les cles Airflow avant le premier `make dev` : `AIRFLOW_FERNET_KEY`, -`AIRFLOW_WEBSERVER_SECRET_KEY`, `AIRFLOW_APP_SECRET_KEY` et `AIRFLOW_ADMIN_PASSWORD`. Sans elles -`airflow-init` refuse de demarrer, et `airflow-webserver` comme `airflow-scheduler` avec lui. +`AIRFLOW_API_SECRET_KEY`, `AIRFLOW_JWT_SECRET`, `AIRFLOW_APP_SECRET_KEY` et +`AIRFLOW_ADMIN_PASSWORD`. Sans elles `airflow-init` refuse de demarrer, et `airflow-apiserver`, +`airflow-scheduler` et `airflow-dag-processor` avec lui. Les cibles d'origine restent disponibles pour ne demarrer qu'une partie : `make db-up`, `make airflow-up`, `make dev-backend`, `make dev-frontend`. diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index e1debb7..971b608 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -25,8 +25,6 @@ services: airflow-apiserver: ports: !override - "127.0.0.1:${AIRFLOW_PORT:-8080}:8080" - environment: - AIRFLOW__WEBSERVER__WORKERS: ${AIRFLOW_WEBSERVER_WORKERS:-2} backend: ports: !reset null diff --git a/docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md b/docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md index 0cc1a66..79c88a8 100644 --- a/docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md +++ b/docs/adr/0009-deux-environnements-compose-sur-la-vm-eni.md @@ -63,8 +63,9 @@ secret. - 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, et 2 workers gunicorn par webserver Airflow. La montée à 32 Go prévue par les - consignes est à demander. + 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. diff --git a/scripts/provision-host.sh b/scripts/provision-host.sh index 0f3d4e1..6bad530 100755 --- a/scripts/provision-host.sh +++ b/scripts/provision-host.sh @@ -47,13 +47,15 @@ preparer() { fi if [[ ! -f "$dossier/.env" ]]; then + local brouillon="$dossier/.env.brouillon" oubliees sed -e "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(secret)|" \ -e "s|^POSTGRES_PORT=.*|POSTGRES_PORT=$port_pg|" \ -e "s|^APP_SECRET_KEY=.*|APP_SECRET_KEY=$(secret)|" \ -e "s|^MAILPIT_UI_PORT=.*|MAILPIT_UI_PORT=$port_mailpit|" \ -e "s|^AIRFLOW_PORT=.*|AIRFLOW_PORT=$port_airflow|" \ -e "s|^AIRFLOW_FERNET_KEY=.*|AIRFLOW_FERNET_KEY=$(fernet)|" \ - -e "s|^AIRFLOW_WEBSERVER_SECRET_KEY=.*|AIRFLOW_WEBSERVER_SECRET_KEY=$(secret)|" \ + -e "s|^AIRFLOW_API_SECRET_KEY=.*|AIRFLOW_API_SECRET_KEY=$(secret)|" \ + -e "s|^AIRFLOW_JWT_SECRET=.*|AIRFLOW_JWT_SECRET=$(secret)|" \ -e "s|^AIRFLOW_ADMIN_PASSWORD=.*|AIRFLOW_ADMIN_PASSWORD=$(secret | cut -c1-20)|" \ -e "s|^AIRFLOW_APP_SECRET_KEY=.*|AIRFLOW_APP_SECRET_KEY=$(secret)|" \ -e "s|^PUBLIC_HOST=.*|PUBLIC_HOST=$hote|" \ @@ -61,13 +63,21 @@ preparer() { -e "s|^COMPOSE_PROJECT_NAME=.*|COMPOSE_PROJECT_NAME=enervision-$env|" \ -e "s|^PROXY_HTTP_PORT=.*|PROXY_HTTP_PORT=$port_http|" \ -e "s|^PROXY_HTTPS_PORT=.*|PROXY_HTTPS_PORT=$port_https|" \ - "$dossier/.env.example" > "$dossier/.env" + "$dossier/.env.example" > "$brouillon" # Branche antérieure à l'ADR 0009 : ces clés manquent alors dans .env.example. for cle in "COMPOSE_PROJECT_NAME=enervision-$env" "PUBLIC_ORIGIN=$origine" \ "PROXY_HTTP_PORT=$port_http" "PROXY_HTTPS_PORT=$port_https"; do - grep -q "^${cle%%=*}=" "$dossier/.env" || echo "$cle" >> "$dossier/.env" + grep -q "^${cle%%=*}=" "$brouillon" || echo "$cle" >> "$brouillon" done - chmod 600 "$dossier/.env" + # Piège : une clé renommée en amont garde sa valeur d'exemple, que le `:?` du compose ne + # voit pas puisqu'elle n'est pas vide. Cas vécu : AIRFLOW_WEBSERVER_SECRET_KEY, Airflow 3. + oubliees="$(grep '=change_me$' "$brouillon" | grep -v '^APP_MOCK_API_' | cut -d= -f1 | tr '\n' ' ' || true)" + if [[ -n "$oubliees" ]]; then + rm -f "$brouillon" + erreur "$env : secrets non générés, .env non écrit : $oubliees" + fi + chmod 600 "$brouillon" + mv "$brouillon" "$dossier/.env" echo "$env : .env généré. Reste à renseigner APP_MOCK_API_USERNAME et APP_MOCK_API_PASSWORD." fi