docs: add server and CI/CD guides
CI / 🔍 Lint & Type Check (push) Successful in 1m37s
CI / 🐳 Build & Push Image (push) Successful in 43s

This commit is contained in:
2026-07-19 21:09:08 +02:00
parent c8a75cb64a
commit fb3d3b5443
13 changed files with 761 additions and 73 deletions
+131
View File
@@ -0,0 +1,131 @@
---
title: Déploiement continu
description: Publier une image puis déployer une version par clé SSH.
---
Le workflow de livraison s'exécute après la CI, idéalement sur un tag de version. Il publie d'abord l'image, puis déclenche une opération étroite et contrôlée sur le serveur.
## Préparer une commande de déploiement côté serveur
Le serveur peut exposer un script `/usr/local/sbin/deploy-app`, appartenant à `root`, qui n'accepte qu'un tag SemVer :
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
tag="${1:-}"
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag invalide" >&2
exit 2
fi
cd /srv/mon-app
printf 'IMAGE_TAG=%s\n' "$tag" > .env.release
docker compose --env-file .env.release -f docker-compose.prod.yml pull
docker compose --env-file .env.release -f docker-compose.prod.yml \
up -d --no-build --remove-orphans
docker compose --env-file .env.release -f docker-compose.prod.yml ps
```
Configure ensuite, avec `visudo`, une règle limitée à ce script pour le compte technique. Le workflow n'a ainsi pas besoin d'un accès Docker général ni d'un mot de passe SSH.
## Publier dans GHCR
```yaml
name: Release
on:
push:
tags: ["v*.*.*"]
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/${{ github.repository }}-backend
tags: type=ref,event=tag
- uses: docker/build-push-action@v6
with:
context: ./backend
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
```
GitHub recommande d'épingler les actions à un SHA de commit pour une chaîne d'approvisionnement plus stricte. Les tags majeurs ci-dessus gardent l'exemple lisible ; remplace-les par les SHA validés par ton équipe en production.
## Déployer avec une clé
Ajoute un second job au même workflow :
```yaml
deploy:
runs-on: ubuntu-latest
needs: publish
permissions:
contents: read
environment:
name: production
url: https://app.example.com
concurrency:
group: production
cancel-in-progress: false
steps:
- name: Préparer SSH
env:
SSH_PRIVATE_KEY: ${{ secrets.PRODUCTION_SSH_PRIVATE_KEY }}
SSH_KNOWN_HOSTS: ${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}
run: |
install -m 700 -d ~/.ssh
printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
printf '%s\n' "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- name: Déployer la version
env:
DEPLOY_HOST: ${{ vars.PRODUCTION_HOST }}
DEPLOY_USER: ${{ vars.PRODUCTION_USER }}
IMAGE_TAG: ${{ github.ref_name }}
run: |
[[ "$IMAGE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
ssh "$DEPLOY_USER@$DEPLOY_HOST" \
"sudo /usr/local/sbin/deploy-app $IMAGE_TAG"
```
## Secrets et variables attendus
| Nom | Type | Contenu |
| --- | --- | --- |
| `PRODUCTION_SSH_PRIVATE_KEY` | secret d'environnement | clé privée dédiée au déploiement |
| `PRODUCTION_SSH_KNOWN_HOSTS` | secret d'environnement | empreinte SSH vérifiée du serveur |
| `PRODUCTION_HOST` | variable d'environnement | nom DNS ou adresse du serveur |
| `PRODUCTION_USER` | variable d'environnement | compte technique autorisé |
La clé doit être dédiée, révocable et limitée à la production. Stocke-la dans l'environnement GitHub `production`, qui peut aussi exiger une approbation et limiter les tags autorisés.
<Callout title="Pas de mot de passe SSH dans la CI" type="warn">
Utilise une clé dédiée et vérifie l'empreinte de l'hôte. Ne remplace pas `known_hosts` par un `ssh-keyscan` aveugle au moment du déploiement.
</Callout>
Pour aller plus loin : [publier des images Docker](https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images) et [protéger les environnements](https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments).
+115
View File
@@ -0,0 +1,115 @@
---
title: Flux complet
description: Relier le développement, la CI, le registry, le serveur et le rollback.
---
Voici le parcours complet d'un changement jusqu'à la production.
<Steps>
<Step>
### Développer un petit changement
Une branche courte part de `main`. Les hooks locaux donnent un premier retour sans remplacer la CI.
</Step>
<Step>
### Ouvrir une pull request
Le frontend et le backend sont vérifiés en parallèle : lint, tests et build.
</Step>
<Step>
### Valider l'image
La CI construit les Dockerfiles de production et peut lancer les tests d'intégration contre la stack Compose.
</Step>
<Step>
### Fusionner sur une branche saine
La fusion n'est possible que si les contrôles obligatoires et la revue ont réussi.
</Step>
<Step>
### Créer une version
Un tag SemVer, par exemple `v1.4.0`, déclenche la publication d'une image portant le même tag.
</Step>
<Step>
### Publier dans le registry
La CI s'authentifie avec un jeton à portée limitée, pousse l'image et conserve son digest.
</Step>
<Step>
### Déployer sur le serveur
L'environnement `production` libère ses secrets après les protections éventuelles. Une clé SSH dédiée appelle le script de déploiement.
</Step>
<Step>
### Vérifier ou restaurer
Healthchecks, URL publique, journaux et smoke test confirment la version. En cas d'échec, le tag précédent est redéployé.
</Step>
</Steps>
## Vue d'ensemble
```text
branche courte
pull request ──► CI ──► revue ──► main
tag de version
build + push de l'image
registry
approbation éventuelle
serveur ──► healthcheck
si échec
tag précédent
```
## Critères de passage
| Passage | Condition |
| --- | --- |
| pull request → main | tous les contrôles et la revue réussissent |
| main → version | la branche est livrable et le changelog est prêt |
| version → registry | l'image est construite et identifiée sans ambiguïté |
| registry → production | sauvegarde, accès, secrets et approbations sont prêts |
| déploiement → terminé | healthchecks et smoke test réussissent |
## En cas d'incident
1. arrête les déploiements concurrents ;
2. collecte le tag, l'heure, les journaux et les changements de configuration ;
3. redéploie le dernier tag sain si l'incident vient de l'application ;
4. restaure les données seulement si nécessaire et selon la procédure testée ;
5. corrige par un nouveau changement versionné, sans modifier le conteneur à la main ;
6. documente la cause et améliore le contrôle qui aurait pu la détecter.
<Callout title="Définition de terminé" type="success">
La pipeline n'est complète que lorsqu'elle sait prouver quelle version tourne, détecter un échec et revenir à un état connu.
</Callout>
+103
View File
@@ -0,0 +1,103 @@
---
title: Intégration continue
description: Organiser des contrôles rapides et bloquants avec GitHub Actions.
---
Un workflow GitHub Actions est un fichier YAML placé dans `.github/workflows/`. Il contient des événements déclencheurs, des jobs et des étapes exécutées par des runners.
## Exemple pour un monorepo
```yaml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: backend/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
docker-build:
runs-on: ubuntu-latest
needs: [backend, frontend]
steps:
- uses: actions/checkout@v6
- run: docker compose -f docker-compose.prod.yml build
```
Le backend et le frontend s'exécutent en parallèle. `docker-build` ne démarre que si les deux ont réussi : il joue le rôle de porte de sortie.
<Callout title="Adapte les scripts au dépôt" type="info">
Les commandes `lint`, `test` et `build` doivent exister dans les `package.json`. Si le projet possède un fichier de version Node, utilise `node-version-file` pour garder la CI alignée avec le développement.
</Callout>
## Installer de façon reproductible
`npm ci` respecte le lockfile et échoue si celui-ci n'est plus cohérent avec `package.json`. Il est préférable à `npm install` dans la CI.
Le cache accélère le téléchargement des paquets, mais ne remplace pas `npm ci`. Les dépendances continuent d'être vérifiées à chaque run.
## Protéger la branche principale
Dans les règles de branche du dépôt :
1. impose une pull request avant fusion ;
2. rends les jobs CI obligatoires ;
3. exige que la branche soit à jour ;
4. empêche la fusion si un job échoue ;
5. limite les contournements administrateur.
## Garder la pipeline lisible
- donne aux jobs des noms qui indiquent leur responsabilité ;
- parallélise les contrôles indépendants ;
- place les tests lents après les vérifications rapides ;
- évite de dupliquer la même logique dans plusieurs workflows ;
- conserve les rapports de test utiles au diagnostic ;
- épingle les actions tierces à un SHA de commit dans les dépôts sensibles.
## Ordre recommandé
```text
format/lint → tests unitaires → build → tests d'intégration → build Docker
```
La [documentation GitHub Actions](https://docs.github.com/en/actions/reference/workflows-and-actions) décrit les événements, jobs, permissions et dépendances disponibles.
+10
View File
@@ -0,0 +1,10 @@
{
"title": "CI/CD",
"description": "Tester, publier et déployer automatiquement",
"pages": [
"principes",
"integration-continue",
"deploiement-continu",
"flux-complet"
]
}
+60
View File
@@ -0,0 +1,60 @@
---
title: Principes de la CI/CD
description: Comprendre la chaîne qui transforme un changement en version déployable.
---
CI/CD désigne un ensemble de pratiques, pas un outil. GitHub Actions, GitLab CI ou Jenkins exécutent la chaîne, mais sa valeur vient surtout de règles simples : retours rapides, branche principale saine et livraison reproductible.
## CI et CD ne font pas le même travail
| Étape | Question | Résultat |
| --- | --- | --- |
| intégration continue (CI) | le changement est-il valide ? | code testé et branche principale saine |
| livraison continue | cette version peut-elle être livrée ? | artefact versionné et prêt |
| déploiement continu (CD) | la version doit-elle être mise en ligne ? | production mise à jour et vérifiée |
Une équipe peut automatiser la livraison tout en gardant une approbation manuelle avant la production. Le « D » de CD ne signifie donc pas toujours déploiement automatique.
## Les trois propriétés recherchées
### Une branche principale toujours livrable
Les branches restent courtes, les changements petits et les contrôles obligatoires avant fusion. Une erreur est plus simple à comprendre lorsqu'elle porte sur quelques commits.
### Des boucles de retour rapides
Lance d'abord les vérifications rapides : formatage, lint et tests unitaires. Les builds Docker et tests e2e plus coûteux viennent ensuite. Un développeur doit savoir rapidement si son changement peut avancer.
### Un artefact unique
La CI produit une image versionnée. La recette de production déploie cette même image ; elle ne reconstruit pas le projet sur le serveur.
```text
commit → contrôles → image versionnée → registry → déploiement → vérification
```
## Répartir les responsabilités
| Niveau | Exemples |
| --- | --- |
| poste du développeur | formatage, lint, tests ciblés, hooks Git |
| pull request | lint complet, tests, build, revue |
| branche principale | image candidate, scans et tests d'intégration |
| version | publication dans le registry |
| environnement | approbation éventuelle, déploiement, smoke test |
Les hooks Git améliorent le confort local, mais la CI reste la source de vérité : un hook peut être désactivé ou ne pas exister sur une autre machine.
## Une politique minimale efficace
- aucune fusion si un contrôle obligatoire échoue ;
- aucun déploiement depuis une branche non approuvée ;
- chaque image porte un tag immuable ;
- les secrets sont limités à l'environnement qui en a besoin ;
- un seul déploiement de production s'exécute à la fois ;
- chaque mise en ligne possède une vérification et un rollback.
<Callout title="La confiance vient de la répétition" type="info">
Une petite pipeline exécutée à chaque changement protège mieux qu'une longue procédure manuelle lancée seulement avant une grosse livraison.
</Callout>