Déploiement : CI/CD GitLab + image frontend de prod + Caddy
Remplace la chaîne GitHub Actions (jamais réellement branchée : aucun remote git n'existait) par une chaîne GitLab CI/CD, et comble un manque qu'elle avait déjà : le frontend n'était jusqu'ici jamais construit ni déployé en production. - `.gitlab-ci.yml` : tests (backend + frontend) à chaque push ; sur `main`, build des images backend et frontend (registre de conteneurs GitLab) puis déploiement SSH sur le VPS (pull, migration Alembic, up -d). - `frontend/Dockerfile.prod` + `frontend/nginx.conf` : build Vite statique servi par nginx (repli SPA sur index.html). `VITE_API_MODE`/ `VITE_EDITION_ID` sont des variables de build, passées en `--build-arg` depuis la variable CI/CD `VITE_EDITION_ID`. - `deploy/docker-compose.prod.yml` : ajout du service `frontend` ; `backend` et `frontend` ne publient plus que sur `127.0.0.1` (Caddy, déjà installé sur le serveur, devient l'unique porte d'entrée publique). - `deploy/Caddyfile.benevoles` : bloc de vhost à ajouter au Caddy existant (`/api/*` vers le backend avec préfixe retiré, le reste vers le frontend). - `deploy/README.md` : runbook complet (remote GitLab, variables CI/CD, préparation du VPS, création de l'édition de production avant le premier build frontend, vhost Caddy). - CLAUDE.md et README.md mis à jour en conséquence. Vérifié : `docker compose -f deploy/docker-compose.prod.yml config`, build réel de l'image frontend de prod, / et une route SPA (/grille) répondent 200 via nginx. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
367dfe42eb
commit
d5f67b2701
+108
-20
@@ -1,24 +1,46 @@
|
||||
# Déploiement
|
||||
|
||||
Le workflow [`.github/workflows/deploy.yml`](../.github/workflows/deploy.yml)
|
||||
se déclenche sur **chaque push sur `main`** :
|
||||
Le pipeline [`.gitlab-ci.yml`](../.gitlab-ci.yml) se déclenche sur **chaque
|
||||
push** :
|
||||
|
||||
1. build de l'image `backend` ;
|
||||
2. push sur `ghcr.io/<owner>/<repo>-backend` (tags `latest` et `sha-<commit>`) ;
|
||||
1. tests (backend : `ruff` + `pytest` + `alembic check` ; frontend :
|
||||
`typecheck` + `lint` + `build` + `smoke`) ;
|
||||
2. sur `main` seulement : build des images `backend` et `frontend`, poussées
|
||||
sur le registre de conteneurs du projet GitLab ;
|
||||
3. copie de `deploy/docker-compose.prod.yml` sur le VPS par SSH ;
|
||||
4. `docker compose -f docker-compose.prod.yml pull && up -d`.
|
||||
4. `docker compose pull`, migration Alembic, `up -d`.
|
||||
|
||||
## Secrets GitHub Actions requis
|
||||
Le VPS n'expose rien directement : un **Caddy déjà installé sur le
|
||||
serveur** (service système, hors de ce dépôt) reçoit le trafic public sur
|
||||
443 et reverse-proxy vers les deux conteneurs, qui n'écoutent que sur
|
||||
`127.0.0.1`.
|
||||
|
||||
| Secret | Description |
|
||||
|----------------|----------------------------------------------------------------|
|
||||
| `SSH_HOST` | Hôte du VPS |
|
||||
| `SSH_USER` | Utilisateur SSH |
|
||||
| `SSH_KEY` | Clé privée SSH (format OpenSSH) |
|
||||
| `DEPLOY_PATH` | Dossier du projet sur le VPS (ex. `/opt/benevoles`) |
|
||||
| `GHCR_TOKEN` | PAT avec scope `read:packages`, pour que le VPS tire l'image |
|
||||
## Étape 0 — pousser le dépôt sur GitLab
|
||||
|
||||
## Préparation du VPS (une fois)
|
||||
```bash
|
||||
# Créer d'abord un projet vide sur GitLab (sans README ni .gitignore), puis :
|
||||
git remote add origin git@gitlab.com:<namespace>/<projet>.git
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
## Variables CI/CD à définir (Paramètres → CI/CD → Variables)
|
||||
|
||||
| Variable | Description |
|
||||
|-------------------|-------------------------------------------------------------------|
|
||||
| `SSH_HOST` | Hôte du VPS |
|
||||
| `SSH_USER` | Utilisateur SSH |
|
||||
| `SSH_KEY` | Clé privée SSH (format OpenSSH) — **masquée**, sur `main` seulement|
|
||||
| `DEPLOY_PATH` | Dossier du projet sur le VPS (ex. `/opt/benevoles`) |
|
||||
| `VITE_EDITION_ID` | UUID de l'édition de production — **à ajouter après** l'étape 3 |
|
||||
|
||||
`CI_REGISTRY`, `CI_REGISTRY_USER`, `CI_REGISTRY_PASSWORD` et
|
||||
`CI_REGISTRY_IMAGE` sont fournies automatiquement par GitLab, rien à
|
||||
configurer.
|
||||
|
||||
La clé publique correspondant à `SSH_KEY` doit être dans le
|
||||
`~/.ssh/authorized_keys` de `SSH_USER` sur le VPS.
|
||||
|
||||
## Étape 1 — préparation du VPS (une fois)
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/benevoles
|
||||
@@ -28,21 +50,87 @@ POSTGRES_USER=benevoles
|
||||
POSTGRES_PASSWORD=<mot de passe fort>
|
||||
POSTGRES_DB=benevoles
|
||||
JWT_SECRET=<secret fort ; openssl rand -hex 32>
|
||||
PUBLIC_BASE_URL=https://benevoles.mon-festival.fr
|
||||
PUBLIC_BASE_URL=https://benevoles.mon-domaine.fr
|
||||
|
||||
# Emails (récapitulatifs de planning + liens de connexion). Laisser
|
||||
# EMAIL_ENABLED=false tant que le SMTP n'est pas prêt : les emails sont alors
|
||||
# seulement journalisés.
|
||||
EMAIL_ENABLED=true
|
||||
SMTP_HOST=smtp.mon-festival.fr
|
||||
SMTP_HOST=smtp.mon-domaine.fr
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=no-reply@mon-festival.fr
|
||||
SMTP_USER=no-reply@mon-domaine.fr
|
||||
SMTP_PASSWORD=<mot de passe SMTP>
|
||||
SMTP_STARTTLS=true
|
||||
SMTP_SSL=false
|
||||
SMTP_FROM=Festival <no-reply@mon-festival.fr>
|
||||
SMTP_FROM=Festival <no-reply@mon-domaine.fr>
|
||||
EOF
|
||||
```
|
||||
|
||||
Le workflow dépose `docker-compose.prod.yml` dans ce dossier et l'utilise tel
|
||||
quel.
|
||||
Le pipeline dépose `docker-compose.prod.yml` dans ce dossier et l'utilise tel
|
||||
quel — il n'y a rien d'autre à y copier.
|
||||
|
||||
## Étape 2 — premier déploiement (backend + base seuls)
|
||||
|
||||
Le frontend a besoin de l'UUID d'une édition pour être construit (voir plus
|
||||
bas) : le tout premier déploiement se fait donc en deux temps.
|
||||
|
||||
1. Sur GitLab, lancer le pipeline sur `main` normalement (Push → CI/CD →
|
||||
Pipelines, ou un simple commit). Le job `build-frontend` échouera ou
|
||||
produira une image sans édition tant que `VITE_EDITION_ID` n'existe pas :
|
||||
c'est attendu, on l'ignore pour l'instant.
|
||||
2. Une fois `build-backend` et `deploy` passés, `db` et `backend` tournent
|
||||
sur le VPS.
|
||||
|
||||
## Étape 3 — créer l'édition de production
|
||||
|
||||
```bash
|
||||
ssh SSH_USER@SSH_HOST
|
||||
cd /opt/benevoles
|
||||
docker compose -f docker-compose.prod.yml run --rm backend \
|
||||
uv run python -m app.bootstrap \
|
||||
--name "Festival 2026" --start 2026-07-01 --end 2026-07-04 \
|
||||
--email coordination@mon-domaine.fr --password <mot-de-passe-solide>
|
||||
```
|
||||
|
||||
La commande affiche l'UUID de l'édition créée. Récupérer aussi celui-ci à
|
||||
tout moment avec :
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml exec -T db \
|
||||
psql -U benevoles -tAc "select id from edition order by created_at desc limit 1"
|
||||
```
|
||||
|
||||
## Étape 4 — brancher le frontend sur cette édition
|
||||
|
||||
Dans GitLab, ajouter la variable CI/CD `VITE_EDITION_ID` avec cet UUID, puis
|
||||
relancer le pipeline sur `main` (bouton *Retry* sur le dernier pipeline, ou un
|
||||
nouveau commit). Cette fois `build-frontend` construit une image qui pointe
|
||||
sur la bonne édition, et `deploy` démarre le service `frontend`.
|
||||
|
||||
`VITE_EDITION_ID` ne change plus ensuite : elle ne se touche à nouveau que
|
||||
pour une nouvelle édition (festival de l'année suivante) qu'on voudrait
|
||||
publier sur ce même domaine.
|
||||
|
||||
## Étape 5 — le vhost Caddy
|
||||
|
||||
Caddy tourne déjà sur ce serveur (service système) : ajouter le bloc
|
||||
[`deploy/Caddyfile.benevoles`](./Caddyfile.benevoles) à son `Caddyfile` (ou au
|
||||
fichier qu'il importe pour les sites), avec le vrai nom de domaine, puis :
|
||||
|
||||
```bash
|
||||
sudo caddy validate --config /etc/caddy/Caddyfile
|
||||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
Le DNS du domaine doit déjà pointer (enregistrement `A`/`AAAA`) vers ce VPS —
|
||||
Caddy obtient et renouvelle seul le certificat HTTPS (Let's Encrypt) au
|
||||
premier accès.
|
||||
|
||||
Vérifier ensuite que `PUBLIC_BASE_URL` dans le `.env` du VPS (étape 1)
|
||||
correspond bien à `https://<ce domaine>` — c'est cette valeur qui est utilisée
|
||||
dans les liens des emails envoyés aux bénévoles.
|
||||
|
||||
## Déploiements suivants
|
||||
|
||||
Un simple push sur `main` suffit : tests → build → déploiement → migration →
|
||||
redémarrage, sans aucune intervention sur le VPS ni sur Caddy.
|
||||
|
||||
Reference in New Issue
Block a user