Pipeline CI/CD¶
Fonctionnement général¶
Le pipeline se déclenche automatiquement à chaque push sur la branche main. Il est identique pour tous les projets (Alert-Parent, Pedago Watch, etc.).
Les 3 jobs¶
Job 1 : Build & Push¶
- Checkout du code source
- Configuration Docker Buildx avec cache GitHub Actions
- Login sur
ghcr.ioavecGITHUB_TOKEN - Build de l'image Docker depuis le
Dockerfile - Push avec deux tags :
sha-XXXXXXX(SHA du commit, pour traçabilité)latest(pour faciliter les pulls manuels)
Job 2 : Deploy¶
- Checkout du code (pour accéder au
docker-compose.yml) - SCP du fichier
docker-compose.ymlvers le VPS (évite legit pullsur le VPS) - SSH vers le VPS, puis :
- Écriture du fichier
.envdepuis le secretDOTENV_FILE - Login sur GHCR via
GITHUB_TOKENpassé en variable d'environnement docker compose pull(télécharge la nouvelle image)docker compose up -d(redémarre le service)- Boucle de health check : 12 tentatives x 5s = 60s max
- Nettoyage des images Docker > 7 jours
Job 3 : Notify¶
Envoie un webhook avec :
- Statut : success ou failure
- SHA du commit
- Acteur (qui a poussé)
- Lien vers le run GitHub Actions
Flux CI/CD¶
sequenceDiagram
participant Dev as Développeur
participant GH as GitHub Actions
participant GHCR as GHCR Registry
participant VPS as VPS Hostinger
Dev->>GH: git push main
GH->>GH: Build Docker image
GH->>GHCR: Push image sha-XXXXXX + latest
GH->>VPS: SCP docker-compose.yml
GH->>VPS: SSH: write .env from DOTENV_FILE
GH->>VPS: SSH: docker login GHCR
GH->>VPS: SSH: docker compose pull && up -d
VPS->>VPS: Health check loop (/health)
GH->>GH: Notify success/failure (webhook)
Secrets GitHub Actions requis¶
| Secret | Description | Obligatoire |
|---|---|---|
SERVER_HOST |
IP ou hostname du VPS | Oui |
SERVER_USERNAME |
Utilisateur SSH (ex: root) |
Oui |
SERVER_SSH_KEY |
Clé privée SSH complète (contenu de ~/.ssh/id_ed25519) |
Oui |
DOTENV_FILE |
Contenu complet du fichier .env de production |
Oui |
WEBHOOK_URL |
URL webhook pour notifications de déploiement | Non |
Configurer les secrets¶
gh secret set SERVER_HOST --repo EpitechAfrik/alert-parent-backend --body "IP_DU_VPS"
gh secret set SERVER_USERNAME --repo EpitechAfrik/alert-parent-backend --body "root"
gh secret set SERVER_SSH_KEY --repo EpitechAfrik/alert-parent-backend < ~/.ssh/id_ed25519
gh secret set DOTENV_FILE --repo EpitechAfrik/alert-parent-backend < .env.prod
Leçons apprises et corrections¶
Utiliser SCP au lieu de git pull¶
Problème : git pull sur le VPS nécessite une clé SSH GitHub configurée sur le VPS pour les repos privés. Cela ajoute de la complexité et des risques de sécurité.
Solution : Le pipeline copie uniquement le docker-compose.yml via SCP. Le code applicatif est dans l'image Docker, pas besoin du repo complet sur le VPS.
Pattern DOTENV_FILE¶
Problème : Gérer des dizaines de secrets individuels dans GitHub Actions est fastidieux et source d'erreurs.
Solution : Stocker l'intégralité du fichier .env comme un seul secret DOTENV_FILE. Le pipeline le réécrit à chaque déploiement sur le VPS.
# Dans le workflow
echo "${{ secrets.DOTENV_FILE }}" > /root/projects/alert-parent/alert-parent-backend/.env
Login GHCR sur le VPS¶
Problème : Le VPS doit s'authentifier auprès de GHCR pour tirer les images des repos privés.
Solution : Le GITHUB_TOKEN est passé en variable d'environnement lors de la session SSH, puis utilisé pour le login.
Chemins absolus¶
Problème : Utiliser ~ ou $HOME dans les scripts SSH peut résoudre vers le mauvais répertoire home (par exemple si l'utilisateur SSH n'est pas root).
Solution : Toujours utiliser des chemins absolus : /root/projects/alert-parent/alert-parent-backend, pas ~/projects/....
Permissions utilisateur¶
Problème : L'utilisateur de déploiement n'avait pas les droits Docker ou les permissions sur les répertoires.
Solutions :
usermod -aG docker UTILISATEUR: ajouter l'utilisateur au groupe Dockerchown UTILISATEUR:UTILISATEUR /root/projects/...: donner la propriété des fichierschmod 711 /rootetchmod 711 /root/projects: permettre la traversée des répertoires
Rollout coordonné frontend/backend pour un gate de droits (breaking change)¶
Problème : Un gate de permission (nouveau droit requis pour voir/faire quelque chose) implique deux repos distincts (frontend + backend). Si le frontend qui vérifie le droit est déployé avant que le backend ne renvoie/n'applique réellement ce droit, des admins qui avaient légitimement accès à une fonctionnalité la voient disparaître de l'UI — une régression visible, le temps que le backend rattrape.
Solution : Construire et tester le gate frontend en avance, mais retenir volontairement son déploiement jusqu'à confirmation explicite que le backend correspondant est live en production. Concrètement (cas vécu : frontend + backend epidocs, coordination entre deux sessions Claude Code travaillant chacune sur son repo) :
- Développer et tester le gate côté frontend sur une branche, sans merger/déployer.
- Attendre la confirmation explicite (message de l'autre session/équipe) que le PR backend correspondant est live en prod — pas seulement mergé.
- Une fois confirmé : commit, push, PR, merge sur
maincôté frontend. - Vérifier le déploiement de bout en bout (voir ci-dessous), pas seulement que la PR a été mergée.
PR mergée ≠ déploiement réussi
Une pull request verte/mergée ne garantit pas que le déploiement en production a réussi — ce sont deux étapes distinctes du pipeline. Un run précédent (sur une autre PR) avait vu le build et les tests passer, puis échouer précisément à l'étape Deploy to Production. Toujours vérifier le run GitHub Actions étape par étape, pas juste son statut global :
En suivant la progression Build & Test → Build Docker Image → Deploy to Production → health-check, et en confirmant que chaque étape est verte, pas uniquement la dernière connue.
Workflow de contribution (branche → PR → CI → merge → déploiement)¶
Procédure suivie systématiquement pour livrer un changement de code sur epidocs-frontend (et applicable tel quel à epidocs-api) — que ce soit une session humaine ou un agent IA qui pousse le code. Aucune de ces étapes n'est spécifique à un outil IA : c'est simplement la discipline attendue avant de merger sur main, qui déclenche un déploiement automatique.
# 1. Toujours vérifier l'état du dépôt avant de commencer (des fichiers
# non liés peuvent déjà être modifiés localement — ne jamais les inclure
# dans le commit par un `git add -A` aveugle)
git status
# 2. Une branche par changement logique, jamais de commit direct sur main
git checkout -b feat/nom-descriptif # ou fix/, selon la nature
# 3. Stager UNIQUEMENT les fichiers du changement en cours
git add chemin/fichier1.js chemin/fichier2.js
# 4. Commit avec un message qui explique le POURQUOI, pas juste le quoi
git commit -m "..."
# 5. Pousser et ouvrir la PR
git push -u origin feat/nom-descriptif
gh pr create --title "..." --body "..."
# 6. Attendre la CI de la PR (pas juste lancer et espérer)
gh pr checks <NUMERO_PR> --watch
# 7. Merger seulement une fois vert
gh pr merge <NUMERO_PR> --merge --delete-branch
# 8. Revenir sur main à jour, retrouver le run de déploiement déclenché par le merge
git checkout main && git pull --ff-only
gh run list --branch main --limit 2
# 9. Vérifier le déploiement de bout en bout, pas juste que la PR est verte
# (voir l'avertissement "PR mergée ≠ déploiement réussi" plus bas)
gh run watch <RUN_ID> --exit-status
gh pr checks --watch peut échouer pour une raison qui n'a rien à voir avec la CI
gh pr checks <N> --watch peut se terminer en erreur (exited with code 1, message error connecting to api.github.com) alors que la CI elle-même est passée — un simple aléa réseau côté gh, pas un échec de check. Toujours relancer gh pr checks <N> (sans --watch) pour lire l'état réel avant de conclure à un échec ou de bloquer un merge.
Pour un changement qui touche un gate de droits partagé frontend/backend
Ne jamais merger/déployer le côté frontend avant confirmation explicite (pas juste "mergé", mais "vérifié live en prod") que le backend correspondant est déployé — voir la section Rollout coordonné frontend/backend ci-dessous. Un moyen rapide de vérifier soi-même qu'une route existe déjà en prod sans avoir de token : curl dessus et vérifier qu'elle répond 401 (authentification requise) plutôt que 404 (route inexistante).
Déploiement manuel¶
Si le pipeline échoue, déployer manuellement :
ssh root@IP_DU_VPS
cd /root/projects/alert-parent/alert-parent-backend
# Mettre à jour le fichier .env si nécessaire
nano .env
# Tirer la dernière image
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
docker compose pull
docker compose up -d
# Vérifier
curl http://127.0.0.1:5011/health