Files
archicratie-edition/docs/OPS-DEPLOYMENT.md
Archicratia 24143fc2c4
All checks were successful
SMOKE / smoke (push) Successful in 3s
CI / build-and-anchors (push) Successful in 36s
CI / build-and-anchors (pull_request) Successful in 37s
chore: <résumé clair de la modif>
2026-03-03 22:12:01 +01:00

441 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OPS — Déploiement Archicratie Web Edition (Mac Studio → DS220+)
Objectif : déployer une nouvelle version du site sur le NAS (DS220+) sans jamais casser la prod, en utilisant un schéma blue/green piloté par DSM Reverse Proxy, avec une procédure robuste même quand docker compose build est instable sur le NAS.
> 🟧 **LEGACY / HISTORIQUE** — Ce document nest plus la source de vérité.
> Référence actuelle : docs/DEPLOY_PROD_SYNOLOGY_DS220.md (canonique).
> Statut : gelé (on nédite plus que pour ajouter un lien vers le canonique, si nécessaire).
> Raison : doublon → risque de divergence → risque derreur en prod.
> Si tu lis ceci pour déployer : stop → ouvre le canonique.
> ⚠️ LEGACY — Ne pas suivre pour déployer.
> Doc conservé pour historique.
> Canon : `DEPLOY_PROD_SYNOLOGY_DS220.md` + `OPS-SYNC-TRIPLE-SOURCE.md`.
## Pourquoi ce doc existe encore
- Historique : il capture des repères (domaines, ports, logique blue/green) tels quils ont été consolidés pendant la phase dimplémentation.
- Sécurité : éviter la divergence documentaire (un seul pas-à-pas officiel).
- Maintenance : si tu dois déployer, tu suis le canonique ; ici tu ne viens que pour comprendre “doù ça vient”.
## Ce quil faut faire aujourdhui (canonique)
➡️ Déploiement = `docs/DEPLOY_PROD_SYNOLOGY_DS220.md` (procédure détaillée, à jour).
## Mise à jour (2026-03-03) — Gate CI de déploiement (SKIP / HOTPATCH / FULL) + preuves A/B
La procédure de déploiement “vivante” est désormais pilotée par **Gitea Actions** via le workflow :
- `.gitea/workflows/deploy-staging-live.yml`
Ce workflow décide automatiquement :
- **FULL** (rebuild + restart blue + green) dès quun changement impacte le build (ex: `src/content/`, `src/pages/`, `scripts/`, `src/anchors/`, etc.)
- **HOTPATCH** (patch JSON + copie media) quand le changement ne concerne que `src/annotations/` et/ou `public/media/`
- **SKIP** sinon
Les preuves et la procédure de test reproductible A/B sont documentées dans :
➡️ `docs/runbooks/DEPLOY-BLUE-GREEN.md` → section “CI Deploy gate (merge-proof) + Tests A/B + preuve alias injection”.
## Schéma (résumé, sans commandes)
- Ne jamais toucher au slot live.
- Construire/tester sur lautre slot.
- Smoke test.
- Bascule DSM Reverse Proxy (8081 ↔ 8082).
- Rollback DSM si besoin.
<details>
> 🚫 NE PAS UTILISER POUR PROD — ARCHIVE UNIQUEMENT
<summary>Archive — ancien pas-à-pas (NE PAS SUIVRE)</summary>
> ⚠️ Archive. Ce contenu est conservé pour mémoire.
## 0) Repères essentiels
Noms & domaines
• Site public (prod) : https://archicratie.trans-hands.synology.me
• Gitea public : https://gitea.archicratie.trans-hands.synology.me
Attention : tu as eu un “piège” de typo (trans-hands-synology.me ≠ trans-hands.synology.me). Toujours vérifier lorthographe exacte.
Ports locaux NAS
• web_blue : 127.0.0.1:8081 → container:80
• web_green : 127.0.0.1:8082 → container:80
• DSM Reverse Proxy pointe soit vers 8081 soit vers 8082.
Règle dor “safe prod”
• On ne touche jamais au slot live (celui pointé par DSM).
• On construit/teste sur lautre slot.
• On bascule DSM (10 secondes).
• On rollback DSM (10 secondes) si besoin.
## 1) Blue/Green : qui fait quoi ?
Convention simple et pro
• blue = slot A (souvent “actif” par défaut) → 8081
• green = slot B (staging/next) → 8082
Mais : la vérité = DSM.
Ce nest pas “blue” ou “green” qui décide : cest le Reverse Proxy DSM qui pointe vers 8081 ou 8082.
➡️ Donc :
• blue et green sont deux environnements identiques
• lun est “live”, lautre est “next”
• après bascule, les rôles sinversent
## 2) Arborescence NAS (standard à stabiliser)
Chemin racine :
• /volume2/docker/archicratie-web/
Sous-dossiers recommandés :
• incoming/ : dépôt darchives venant du Mac (upload File Station / scp)
• releases/ : releases dépliées, horodatées
• current : symlink vers la release “courante” (le code utilisé pour builder)
• ops/ : scripts dexploitation (smoke, which-live, helpers)
• current__backup_before_cleanup/ : backup historique (optionnel)
Exemple sain :
/volume2/docker/archicratie-web/
incoming/
archicratie-web-20260130-104937.tar.gz
archicratie-web-20260130-104937.tar.gz.sha256
releases/
20260130-104937/
app/ (code déplié prêt)
current -> releases/20260130-104937/app
ops/
smoke.sh
which-live.sh
## 3) Permissions NAS (ce qui est “propre”)
Tu as eu des problèmes de release dépliée “root:root” → impossible à lire en user.
Politique simple
• propriétaire : archicratia:users
• dossiers : 750
• fichiers : 640
• incoming peut être 770 si tu y upload souvent via File Station.
Commandes (à lancer à la racine) :
BASE="/volume2/docker/archicratie-web"
sudo chown -R archicratia:users "$BASE"
sudo chmod 750 "$BASE" "$BASE/ops" "$BASE/releases" "$BASE/current__backup_before_cleanup" 2>/dev/null || true
sudo chmod 770 "$BASE/incoming" 2>/dev/null || true
# Important : options find AVANT les tests
find "$BASE/releases" -maxdepth 3 -type d -exec chmod 750 {} \;
find "$BASE/releases" -maxdepth 3 -type f -exec chmod 640 {} \;
⚠️ Éviter chmod 700 * “au hasard” : ça peut te bloquer toi-même + bloquer des outils DSM.
Le trio 750/640 est ton bon compromis.
## 4) Variables Gitea (les 3 variables qui conditionnent “Proposer”)
Dans .env sur le NAS (dans current/ ou dans la release) :
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
PUBLIC_GITEA_OWNER=Archicratia
PUBLIC_GITEA_REPO=archicratie-edition
Point critique : la casse du OWNER
Tu as déjà vu le symptôme :
• archicratia/archicratie-edition → peut renvoyer 404
• Archicratia/archicratie-edition → OK
Donc : OWNER doit être exactement la casse que Gitea attend.
Test rapide (NAS) :
BASE="https://gitea.archicratie.trans-hands.synology.me"
curl -kI "$BASE/Archicratia/archicratie-edition/" | head -n 8
✅ attendu : HTTP/2 200
## 5) Côté Mac Studio : préparer une release “propre” (sans scories macOS)
Pourquoi
Tu as eu :
• fichiers ._*
• xattrs LIBARCHIVE.xattr.com.apple.*
• warnings à lextraction
➡️ Ce nest pas bloquant, mais cest sale et ça te pollue les releases.
Script Mac : release-pack.sh (sans Git, ultra simple)
À placer à la racine du repo site/ sur Mac.
#!/bin/zsh
set -euo pipefail
TS="${1:-$(date +%Y%m%d-%H%M%S)}"
NAME="archicratie-web-$TS"
OUT_DIR="_release_out"
ARCHIVE="$OUT_DIR/$NAME.tar.gz"
SHA="$ARCHIVE.sha256"
mkdir -p "$OUT_DIR"
### Évite les AppleDouble (._*) + certaines métadonnées
export COPYFILE_DISABLE=1
export COPY_EXTENDED_ATTRIBUTES_DISABLE=1
### Nettoyages “safe”
find . -name ".DS_Store" -delete 2>/dev/null || true
### Crée un dossier staging
STAGE="$(mktemp -d)"
mkdir -p "$STAGE/$NAME"
### Copie le repo SANS déchets
rsync -a --delete \
--exclude ".git/" \
--exclude "node_modules/" \
--exclude "dist/" \
--exclude ".astro/" \
--exclude "_release_out/" \
--exclude ".DS_Store" \
--exclude "__MACOSX/" \
--exclude "._*" \
./ "$STAGE/$NAME/"
### Tar propre
tar -czf "$ARCHIVE" -C "$STAGE" "$NAME"
### Checksum
shasum -a 256 "$ARCHIVE" > "$SHA"
echo "OK: $ARCHIVE"
echo "OK: $SHA"
Usage :
chmod +x release-pack.sh
./release-pack.sh 20260130-104937
Résultat :
• _release_out/archicratie-web-20260130-104937.tar.gz
• _release_out/archicratie-web-20260130-104937.tar.gz.sha256
## 6) Transfert vers le NAS
Option A — DSM File Station (simple)
• Upload les 2 fichiers dans :
◦ /volume2/docker/archicratie-web/incoming/
Option B — scp (si SSH)
Depuis le Mac :
scp _release_out/archicratie-web-20260130-104937.tar.gz* \
archicratia@192.168.1.20:/volume2/docker/archicratie-web/incoming/
## 7) NAS : vérifier + déplier une release (procédure canonique)
BASE="/volume2/docker/archicratie-web"
TS="20260130-104937"
cd "$BASE"
### 1) checksum (IMPORTANT)
sha256sum -c "incoming/archicratie-web-$TS.tar.gz.sha256"
### 2) créer dossier release
rm -rf "releases/$TS"
mkdir -p "releases/$TS"
### 3) extraire
tar -xzf "incoming/archicratie-web-$TS.tar.gz" -C "releases/$TS"
### 4) pointer APP vers le dossier extrait
APP="$BASE/releases/$TS/archicratie-web-$TS"
### option: normaliser en "app"
mv "$APP" "$BASE/releases/$TS/app"
APP="$BASE/releases/$TS/app"
### 5) ownership + perms
sudo chown -R archicratia:users "$BASE/releases/$TS"
find "$BASE/releases/$TS" -type d -exec chmod 750 {} \;
find "$BASE/releases/$TS" -type f -exec chmod 640 {} \;
### 6) basculer current (symlink)
ln -sfn "$APP" "$BASE/current"
### 7) sanity check : compose présent ?
ls -la "$BASE/current/docker-compose.yml" "$BASE/current/Dockerfile" "$BASE/current/nginx.conf" "$BASE/current/.env"
Cas réel déjà rencontré : la release “na pas les fichiers ops”
Tu as eu un tar “inner” (archicratie-web.tar.gz) qui nembarque pas docker-compose.yml/Dockerfile/nginx.conf/.env.
Règle pro : ces fichiers doivent être dans la release.
Fix immédiat si cest absent (tu las déjà fait) :
OPS_SRC="$BASE/releases/20260129-174516_clean"
cp -a "$OPS_SRC/docker-compose.yml" "$APP/"
cp -a "$OPS_SRC/Dockerfile" "$APP/"
cp -a "$OPS_SRC/nginx.conf" "$APP/"
cp -a "$OPS_SRC/.env" "$APP/.env"
## 8) Build GREEN sur NAS (robuste) — IMPORTANT
Pourquoi docker compose build nest PAS fiable sur DS220+
Tu as vu :
• Temporary failure resolving 'deb.debian.org'
• apt-get update qui part en Ign: puis Err:
➡️ En pratique sur ton NAS : le builder na pas toujours le bon réseau, même si build: network: host est déclaré.
Procédure “qui marche vraiment” (golden path)
➡️ On build en host network avec docker build, puis on déploie avec compose sans rebuild.
cd /volume2/docker/archicratie-web/current
### charge les env vars du .env
set -a
. ./.env
set +a
### BUILD image green (host network)
sudo docker build --no-cache --network host \
--build-arg PUBLIC_GITEA_BASE="$PUBLIC_GITEA_BASE" \
--build-arg PUBLIC_GITEA_OWNER="$PUBLIC_GITEA_OWNER" \
--build-arg PUBLIC_GITEA_REPO="$PUBLIC_GITEA_REPO" \
-t archicratie-web:green \
-f Dockerfile .
Voir Ign: pendant apt-get nest pas forcément une erreur.
Ce qui compte : est-ce quil finit par télécharger / réussir.
On salarme uniquement si on voit Err: ... Temporary failure resolving + exit code non-zéro.
## 9) Démarrer GREEN (sans impacter BLUE)
cd /volume2/docker/archicratie-web/current
# ne jamais lancer "up" sans préciser le service
sudo docker rm -f archicratie-web-green 2>/dev/null || true
sudo docker compose up -d --force-recreate --no-build web_green
Smoke test (port 8082) :
/volume2/docker/archicratie-web/ops/smoke.sh 8082
## 10) DSM : basculer le Reverse Proxy (10 secondes)
DSM → Panneau de configuration → Portail de connexion (ou “Portail des applications”) → Proxy inversé
Trouve la règle :
• Source : https://archicratie.trans-hands.synology.me (443)
Destination :
• pour BLUE : http://127.0.0.1:8081
• pour GREEN : http://127.0.0.1:8082
Tu changes seulement le port, tu “Appliques”.
Test immédiat :
curl -kI https://archicratie.trans-hands.synology.me/ | head -n 8
## 11) Rollback (10 secondes)
Si ça ne va pas :
• DSM Reverse Proxy → remettre lancien port (8081 ou 8082)
• refresh navigateur
Option pro : ne stoppe pas lautre container tout de suite (tu peux comparer / investiguer calmement).
## 12) Ops scripts (à garder dans /volume2/docker/archicratie-web/ops)
smoke.sh (version “complète”)
#!/bin/sh
set -eu
PORT="${1:-8081}"
BASE="http://127.0.0.1:${PORT}"
echo "Smoke test ${BASE}"
curl -fsSI "${BASE}/" | head -n 5
curl -fsSI "${BASE}/pagefind/pagefind.js" | head -n 5
curl -fsSI "${BASE}/pagefind/pagefind-ui.js" | head -n 5 || true
curl -fsSI "${BASE}/pagefind/pagefind-ui.css" | head -n 5 || true
curl -fsSI "${BASE}/pagefind/pagefind-entry.json" | head -n 5 || true
echo "OK"
which-live.sh (déduire quel port est live)
Idée : on compare les Last-Modified ou ETag entre le domaine public et les ports locaux.
#!/bin/sh
set -eu
DOMAIN="https://archicratie.trans-hands.synology.me"
A="http://127.0.0.1:8081"
B="http://127.0.0.1:8082"
etag() { curl -ksI "$1/" | awk -F': ' 'tolower($1)=="etag"{print $2}' | tr -d '\r'; }
lm() { curl -ksI "$1/" | awk -F': ' 'tolower($1)=="last-modified"{print $2}' | tr -d '\r'; }
E_D="$(etag "$DOMAIN")"
E_A="$(etag "$A")"
E_B="$(etag "$B")"
echo "DOMAIN ETag: $E_D"
echo "8081 ETag: $E_A"
echo "8082 ETag: $E_B"
if [ -n "$E_D" ] && [ "$E_D" = "$E_A" ]; then
echo "LIVE=8081 (blue slot probable)"
elif [ -n "$E_D" ] && [ "$E_D" = "$E_B" ]; then
echo "LIVE=8082 (green slot probable)"
else
echo "LIVE=INCONNU (ETag mismatch) — check Last-Modified:"
echo "DOMAIN: $(lm "$DOMAIN")"
echo "8081 : $(lm "$A")"
echo "8082 : $(lm "$B")"
fi
## 13) Pannes & diagnostics (les vrais cas rencontrés)
### A) 504 via DSM Reverse Proxy
Symptôme : HTTP/2 504 côté domaine.
Check :
1. le container répond en local :
curl -I http://127.0.0.1:8081/
curl -I http://127.0.0.1:8082/
2. DSM Reverse Proxy destination = http://127.0.0.1:808X (pas https)
3. ports bindés en loopback (recommandé) : 127.0.0.1:808X:80
4. logs container :
sudo docker logs --tail=80 archicratie-web-blue
sudo docker logs --tail=80 archicratie-web-green
### B) “Proposer” ouvre Gitea mais tombe sur 404
Cest quasiment toujours lun de ces trois points :
1. OWNER/REPO incorrects (casse)
Test :
BASE="https://gitea.archicratie.trans-hands.synology.me"
curl -kI "$BASE/Archicratia/archicratie-edition/" | head
• Si 404 → cest ton .env / build args.
• La build a embarqué une ancienne config
Vérifie dans le HTML servi (dans le container) :
sudo docker exec -it archicratie-web-green sh -lc \
'grep -Rin "const GITEA_BASE" /usr/share/nginx/html | head -n 20'
1. Tu dois voir https://gitea.archicratie.trans-hands.synology.me + bon OWNER/REPO.
2. Problème dauth / droits Gitea
Si tu es loggé mais “pas autorisé”, vérifier que tu as accès au repo et que lURL pointe au bon repo.
### C) “Proposer” échoue avant Gitea (pas de pop-up, pas de 2 choix)
Check :
• console navigateur (JS)
• vérifier que le script “Proposer” est bien injecté dans la page (view source)
• tester une page simple (ex: /archicratie/)
### D) Pagefind nindexe plus
Ce que tu as déjà observé :
• Pagefind ignore les pages sans data-pagefind-body
• Tu avais bien ~12 pages indexées (log Pagefind)
Check dans le container :
sudo docker exec -it archicratie-web-green sh -lc \
'ls -la /usr/share/nginx/html/pagefind | head'
Note :
• GET /pagefind/ peut renvoyer 403 (listing interdit) : ce nest pas un bug
• tu testes plutôt :
◦ /pagefind/pagefind.js
◦ /pagefind/pagefind-entry.json
### E) docker compose build casse sur apt-get update (DNS)
Symptôme :
• Temporary failure resolving 'deb.debian.org'
Diagnostic rapide :
sudo docker run --rm --network host node:22-bookworm-slim sh -lc \
'apt-get -o Acquire::ForceIPv4=true update -qq && echo OK_APT'
✅ si OK_APT : ton NAS sait sortir, cest le builder compose qui est instable → utiliser la golden path : docker build --network host.
## 14) Dockerfile : version robuste “NAS host-network”
Dans ton Dockerfile, garde :
RUN --network=host apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& rm -rf /var/lib/apt/lists/*
Option “anti-fragile” (retries + IPv4) :
RUN --network=host apt-get -o Acquire::Retries=5 -o Acquire::ForceIPv4=true update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& rm -rf /var/lib/apt/lists/*
## 15) Important : ne pas se faire piéger par le docker.sock
Sur ton DS220+, /var/run/docker.sock est root:root avec 660 → ton user ne peut pas accéder Docker sans sudo.
➡️ Règle :
• commandes Docker = sudo docker ...
• compose = sudo docker compose ...
(Optionnel : alias)
alias d='sudo docker'
alias dc='sudo docker compose'
## 16) Workflow résumé “cockpit” (le plus important)
Depuis le Mac :
1. ./release-pack.sh 20260130-104937
2. upload _release_out/*.tar.gz* → NAS incoming/
Sur le NAS :
1. vérifier checksum
2. déplier releases/$TS + chown/chmod
3. ln -sfn releases/$TS/app current
4. build green :
◦ sudo docker build --network host ... -t archicratie-web:green .
5. run green :
◦ sudo docker compose up -d --force-recreate --no-build web_green
6. smoke :
◦ /volume2/docker/archicratie-web/ops/smoke.sh 8082
7. switch DSM Reverse Proxy 8081 ↔ 8082
8. si souci → rollback DSM
Post-scriptum : ton problème local Mac (Astro “Cannot find module astro/config”)
Ce symptôme arrive typiquement quand :
• node_modules est incomplet/corrompu
• tu as basculé de dossier (ex: un _release_out/... a été pris pour le vrai repo)
• ou le process dev a reload sur un tsconfig “nouveau” mais pas les deps
Fix standard (dans le vrai dossier site/) :
rm -rf node_modules .astro dist
npm ci
npm run dev
</details>