diff --git a/content/docs/ci-cd/deploiement-continu.mdx b/content/docs/ci-cd/deploiement-continu.mdx new file mode 100644 index 0000000..52696f5 --- /dev/null +++ b/content/docs/ci-cd/deploiement-continu.mdx @@ -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. + + + 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. + + +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). diff --git a/content/docs/ci-cd/flux-complet.mdx b/content/docs/ci-cd/flux-complet.mdx new file mode 100644 index 0000000..a6b65f3 --- /dev/null +++ b/content/docs/ci-cd/flux-complet.mdx @@ -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. + + + + + ### Développer un petit changement + + Une branche courte part de `main`. Les hooks locaux donnent un premier retour sans remplacer la CI. + + + + + ### Ouvrir une pull request + + Le frontend et le backend sont vérifiés en parallèle : lint, tests et build. + + + + + ### Valider l'image + + La CI construit les Dockerfiles de production et peut lancer les tests d'intégration contre la stack Compose. + + + + + ### Fusionner sur une branche saine + + La fusion n'est possible que si les contrôles obligatoires et la revue ont réussi. + + + + + ### Créer une version + + Un tag SemVer, par exemple `v1.4.0`, déclenche la publication d'une image portant le même tag. + + + + + ### Publier dans le registry + + La CI s'authentifie avec un jeton à portée limitée, pousse l'image et conserve son digest. + + + + + ### 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. + + + + + ### 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é. + + + + +## 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. + + + La pipeline n'est complète que lorsqu'elle sait prouver quelle version tourne, détecter un échec et revenir à un état connu. + + diff --git a/content/docs/ci-cd/integration-continue.mdx b/content/docs/ci-cd/integration-continue.mdx new file mode 100644 index 0000000..634f210 --- /dev/null +++ b/content/docs/ci-cd/integration-continue.mdx @@ -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. + + + 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. + + +## 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. + diff --git a/content/docs/ci-cd/meta.json b/content/docs/ci-cd/meta.json new file mode 100644 index 0000000..f2c38b1 --- /dev/null +++ b/content/docs/ci-cd/meta.json @@ -0,0 +1,10 @@ +{ + "title": "CI/CD", + "description": "Tester, publier et déployer automatiquement", + "pages": [ + "principes", + "integration-continue", + "deploiement-continu", + "flux-complet" + ] +} diff --git a/content/docs/ci-cd/principes.mdx b/content/docs/ci-cd/principes.mdx new file mode 100644 index 0000000..d8ad56f --- /dev/null +++ b/content/docs/ci-cd/principes.mdx @@ -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. + + + Une petite pipeline exécutée à chaque changement protège mieux qu'une longue procédure manuelle lancée seulement avant une grosse livraison. + + diff --git a/content/docs/index.mdx b/content/docs/index.mdx index 2d370be..19be73b 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -1,9 +1,9 @@ --- -title: Docker - Support de cours -description: Comprendre les images, les conteneurs, Compose, le réseau, le déploiement et les tests. +title: Docker, déploiement et CI/CD +description: Comprendre les conteneurs, préparer un serveur et automatiser une livraison de bout en bout. --- -Ce cours explique pourquoi Docker est utile, comment il fonctionne et comment l'utiliser sur une application complète. Le contenu du support PDF a été réorganisé en chapitres courts pour faciliter la lecture et la recherche. +Ce cours explique pourquoi Docker est utile, comment il fonctionne et comment l'utiliser sur une application complète. Les supports ont été réorganisés en chapitres courts qui vont du premier conteneur jusqu'au déploiement automatisé. Lis les chapitres dans l'ordre lors d'une première découverte. Les liens « Page précédente » et « Page suivante » permettent de suivre le cours sans revenir au sommaire. @@ -18,7 +18,9 @@ Ce cours explique pourquoi Docker est utile, comment il fonctionne et comment l' - optimiser le cache de build et utiliser un build multi-stage ; - orchestrer plusieurs services avec Docker Compose ; - gérer la persistance, les réseaux et les ports ; -- déployer une image construite par une CI/CD ; +- préparer et sécuriser un serveur de production ; +- construire une pipeline d'intégration et de déploiement continus ; +- déployer, vérifier puis restaurer une image versionnée ; - lancer une infrastructure de test isolée avec Testcontainers. ## Plan @@ -36,8 +38,14 @@ Ce cours explique pourquoi Docker est utile, comment il fonctionne et comment l' Une stack React, NestJS, PostgreSQL et Nginx de bout en bout. - - Construire une fois, publier dans un registry et exécuter partout. + + Sécuriser SSH, limiter les ports et préparer un hôte Docker. + + + Livrer une image versionnée, contrôler sa santé et revenir en arrière. + + + Valider le code, publier les images et automatiser la mise en production. Infrastructure réelle, isolée et jetable pour les tests e2e. @@ -46,10 +54,10 @@ Ce cours explique pourquoi Docker est utile, comment il fonctionne et comment l' ## Le fil conducteur -**Code et Dockerfile** → docker build → **image** → docker run ou docker compose up → **conteneur** +**Code et Dockerfile** → CI → **image versionnée** → registry → déploiement → **conteneur vérifié** -Une image est un artefact figé et reproductible. Un conteneur est une instance vivante de cette image. Docker Compose permet ensuite de lancer et relier plusieurs conteneurs comme une seule application. +Une image est un artefact figé et reproductible. Un conteneur est une instance vivante de cette image. Docker Compose lance la stack ; la CI/CD garantit que l'image testée est celle qui atteint le serveur. ## Accès rapide -Si tu connais déjà les bases, tu peux aller directement au [cas pratique complet](/docs/cas-pratique/react-nest-postgresql) ou au [récapitulatif](/docs/recapitulatif). +Si tu connais déjà les bases, va directement au [cas pratique complet](/docs/cas-pratique/react-nest-postgresql), à la [préparation du serveur](/docs/serveur/bien-demarrer), au [flux CI/CD complet](/docs/ci-cd/flux-complet) ou au [récapitulatif](/docs/recapitulatif). diff --git a/content/docs/meta.json b/content/docs/meta.json index deb2215..2b0cba4 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -6,7 +6,9 @@ "images-et-builds", "orchestration", "cas-pratique", + "serveur", "production", + "ci-cd", "tests", "recapitulatif" ] diff --git a/content/docs/production/deploiement.mdx b/content/docs/production/deploiement.mdx index 8496dd3..3b88be5 100644 --- a/content/docs/production/deploiement.mdx +++ b/content/docs/production/deploiement.mdx @@ -1,78 +1,129 @@ --- -title: Déploiement avec Docker -description: Construire les images, les publier puis les exécuter sur le serveur. +title: Déployer avec Docker +description: Livrer une image versionnée, vérifier sa santé et revenir en arrière. --- -Une fois l'application dockerisée, le déploiement suit une chaîne simple : +Le déploiement commence après la CI. Les tests ont réussi et une image immuable a été publiée dans un registry : ```text -build des images - ↓ -push vers un registry - ↓ +image testée et versionnée + ↓ pull sur le serveur - ↓ -docker compose up + ↓ +remplacement des conteneurs + ↓ +contrôles de santé ``` -Une CI/CD, par exemple GitHub Actions, automatise cette chaîne. + + Le serveur ne recompile rien. Il lance exactement l'image produite et validée par la CI. + -## CI : garder la branche saine - -Sur chaque push vers la branche principale : - -| Job | Contenu | -| --- | --- | -| `backend-checks` | lint, build, tests unitaires et tests e2e | -| `frontend-checks` | lint, build et tests | -| `build-images` | construction des images avec le fichier Compose de production | - -Le job de build vérifie que les Dockerfiles continuent de produire des images valides. - -## CD : publier une version - -Lorsqu'un tag de version est poussé : - -| Job | Contenu | -| --- | --- | -| Vérifications | Les mêmes contrôles que la CI | -| `build-and-push` | Build des images et push vers Docker Hub, GHCR ou un autre registry | -| `deploy` | Copie de la configuration puis connexion SSH au serveur | - -## Build une fois, run partout - -Le serveur ne recompile rien. Il récupère exactement l'image construite et testée par la CI : - -```bash -docker compose pull -docker compose up -d --no-build -docker image prune -f -``` - -`--no-build` garantit que le serveur lance les images récupérées sans reconstruire depuis le code source. - -## image et build dans le Compose de production +## Préparer le Compose de production ```yaml services: backend: - image: registry.example.com/mon-app/backend:${IMAGE_TAG:-latest} - build: - context: ./backend - dockerfile: Dockerfile + image: ghcr.io/organisation/mon-app-backend:${IMAGE_TAG:?IMAGE_TAG requis} + restart: unless-stopped + env_file: + - .env.prod + healthcheck: + test: + - CMD + - node + - -e + - fetch('http://localhost:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1)) + interval: 10s + timeout: 3s + retries: 5 + start_period: 20s + + postgres: + image: postgres:16-alpine + restart: unless-stopped + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: ``` -Dans la CI, `build:` sert à construire puis pousser l'image. En production, le serveur utilise `image:` et `--no-build` pour exécuter le tag déjà publié. +Le tag doit identifier une version précise, par exemple `v1.4.0` ou un SHA de commit. Évite `latest`, qui ne permet pas de savoir sans ambiguïté ce qui tourne. -Le serveur n'a besoin ni du code source, ni de Node.js, ni du toolchain de compilation. Il lui faut seulement Docker, le fichier Compose et un accès au registry. +## Déployer une version -## Ce que Docker apporte +Dans `/srv/mon-app`, écris le tag choisi dans `.env.release` : -- **Reproductibilité** : l'image testée par la CI est celle qui tourne en production. -- **Rollback simple** : revenir en arrière revient à redéployer le tag précédent. -- **Serveur minimal** : toutes les versions et dépendances vivent dans les images. -- **Immutabilité** : on remplace une image complète au lieu de modifier le serveur en place. +```dotenv +IMAGE_TAG=v1.4.0 +``` - - Construis une fois et exécute partout. Une image versionnée est l'unité de livraison ; le tag identifie précisément la version déployée. +Puis récupère et lance les images : + +```bash +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 +``` + +`--no-build` empêche toute reconstruction sur le serveur. Les données vivent dans les volumes et ne sont pas supprimées par le remplacement des conteneurs. + +## Vérifier immédiatement + +```bash +docker compose -f docker-compose.prod.yml ps +docker compose -f docker-compose.prod.yml logs --tail=100 +curl --fail --show-error https://app.example.com/health +``` + +Un déploiement n'est réussi que lorsque : + +- les conteneurs sont démarrés et en bonne santé ; +- les migrations de données ont terminé ; +- l'URL publique répond ; +- les journaux ne montrent pas de boucle d'erreurs ; +- une action métier courte fonctionne. + +## Revenir à la version précédente + +Un rollback réutilise l'ancien tag : + +```dotenv +IMAGE_TAG=v1.3.2 +``` + +Relance ensuite `pull` puis `up -d --no-build`. Conserve au moins quelques versions dans le registry pour rendre ce retour possible. + + + Une image peut revenir en arrière, mais une migration destructive de base de données peut être irréversible. Préfère des migrations rétrocompatibles en plusieurs étapes et sauvegarde avant les changements sensibles. + +## Ce qui est déployé et ce qui persiste + +| Élément | Comportement | +| --- | --- | +| image applicative | remplacée à chaque version | +| conteneur | recréé à partir de l'image | +| fichier Compose | versionné et copié explicitement | +| secrets | conservés hors de Git sur le serveur ou dans un coffre | +| volume de données | persiste entre les déploiements et doit être sauvegardé | +| journaux | collectés et soumis à une rotation | + +## Checklist + +- [ ] image versionnée disponible dans le registry ; +- [ ] sauvegarde récente et restauration déjà testée ; +- [ ] tag de la version précédente connu ; +- [ ] configuration et secrets présents sur le serveur ; +- [ ] healthchecks opérationnels ; +- [ ] déploiement sérialisé pour éviter deux mises à jour simultanées ; +- [ ] vérification fonctionnelle et rollback documentés. + +La rubrique [CI/CD](/docs/ci-cd/principes) automatise maintenant ces étapes sans confondre validation, publication et mise en production. diff --git a/content/docs/production/meta.json b/content/docs/production/meta.json index 0168f3a..910f967 100644 --- a/content/docs/production/meta.json +++ b/content/docs/production/meta.json @@ -1,5 +1,5 @@ { - "title": "Production", - "description": "Livrer et exécuter les images", + "title": "Déploiement", + "description": "Livrer, vérifier et restaurer une version", "pages": ["deploiement"] } diff --git a/content/docs/recapitulatif.mdx b/content/docs/recapitulatif.mdx index 163a050..0603bef 100644 --- a/content/docs/recapitulatif.mdx +++ b/content/docs/recapitulatif.mdx @@ -14,7 +14,10 @@ description: Toutes les notions du cours Docker en une page. | Volume | Stockage persistant découplé du conteneur et géré par Docker. | | Réseau | Réseau bridge privé où les services se joignent par leur nom. | | Mapping de ports | Publie un port du conteneur vers l'hôte ; le reste demeure interne. | -| Déploiement | Build une fois, push dans un registry, puis pull et run sur le serveur. | +| Serveur | Accès par clé, compte non-root, ports minimaux, correctifs et sauvegardes testées. | +| CI | Vérifie chaque changement avant qu'il atteigne la branche principale. | +| CD | Publie une image versionnée puis déploie la même image dans un environnement protégé. | +| Déploiement | Pull d'un tag immuable, remplacement des conteneurs, contrôles de santé et rollback. | | Testcontainers | Infrastructure réelle, isolée et jetable, démarrée par les tests. | ## Les commandes essentielles @@ -52,9 +55,12 @@ docker compose up -d --no-build 5. Stocke les données persistantes dans des volumes sauvegardés. 6. Utilise les noms de services, pas `localhost`, entre conteneurs. 7. Ne publie que les ports réellement nécessaires. -8. Construis l'image dans la CI et exécute cette même image en production. -9. Préfère une infrastructure de test réelle et isolée lorsque l'intégration compte. +8. Sécurise le serveur et teste les sauvegardes avant le premier déploiement. +9. Construis l'image dans la CI et exécute cette même image en production. +10. Versionne chaque image et conserve le tag précédent pour le rollback. +11. Déploie avec une clé dédiée et des permissions limitées. +12. Préfère une infrastructure de test réelle et isolée lorsque l'intégration compte. - Tu peux maintenant revenir au [cas pratique](/docs/cas-pratique/react-nest-postgresql) pour relire l'ensemble des concepts dans une seule stack. + Reviens au [cas pratique](/docs/cas-pratique/react-nest-postgresql) pour la stack applicative, puis suis le [flux CI/CD complet](/docs/ci-cd/flux-complet) pour aller jusqu'à la production. diff --git a/content/docs/serveur/bien-demarrer.mdx b/content/docs/serveur/bien-demarrer.mdx new file mode 100644 index 0000000..a5474e6 --- /dev/null +++ b/content/docs/serveur/bien-demarrer.mdx @@ -0,0 +1,111 @@ +--- +title: Bien démarrer un serveur +description: Sécuriser les accès et poser une base saine avant le premier déploiement. +--- + +Un serveur de production doit être préparé **avant** d'héberger l'application. L'objectif du premier jour est simple : réduire la surface d'attaque, conserver un accès de secours et automatiser les mises à jour de sécurité. + + + Garde ta première session SSH ouverte pendant les changements. Valide la configuration, puis ouvre une deuxième session avec la clé avant de désactiver les mots de passe. + + +## 1. Mettre le système à jour + +```bash +sudo apt update +sudo apt full-upgrade -y +sudo reboot +``` + +Après le redémarrage, reconnecte-toi et vérifie que les services essentiels sont revenus. + +## 2. Créer un compte d'administration + +Le compte `root` ne doit pas être utilisé pour les connexions quotidiennes : + +```bash +sudo adduser deploy +sudo usermod -aG sudo deploy +``` + +Ce compte servira à administrer et déployer l'application. Pour une équipe, préfère un compte nominatif par personne et un compte technique distinct pour l'automatisation. + +## 3. Utiliser une clé SSH + +Génère la clé sur ta machine, jamais sur le serveur : + +```bash +ssh-keygen -t ed25519 -a 100 -f ~/.ssh/serveur_production +ssh-copy-id -i ~/.ssh/serveur_production.pub deploy@ADRESSE_IP +``` + +Teste ensuite la connexion dans un nouveau terminal : + +```bash +ssh -i ~/.ssh/serveur_production deploy@ADRESSE_IP +``` + +Quand cet accès fonctionne, ajoute un fichier `/etc/ssh/sshd_config.d/99-hardening.conf` : + +```text +PermitRootLogin no +PasswordAuthentication no +PubkeyAuthentication yes +``` + +Valide **avant** de recharger SSH : + +```bash +sudo sshd -t +sudo systemctl reload ssh +``` + +## 4. Fermer les ports inutiles + +Pour un serveur web classique, seuls SSH, HTTP et HTTPS sont nécessaires : + +```bash +sudo ufw allow OpenSSH +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +sudo ufw enable +sudo ufw status verbose +``` + +Applique les mêmes restrictions dans le pare-feu du fournisseur cloud. + + + Un port publié par Docker peut contourner les règles UFW. Ne publie vers l'hôte que les ports du reverse proxy, vérifie aussi le pare-feu du fournisseur et utilise la chaîne Docker DOCKER-USER si tu dois filtrer le trafic des conteneurs. + + +## 5. Automatiser les correctifs de sécurité + +```bash +sudo apt install unattended-upgrades +sudo dpkg-reconfigure -plow unattended-upgrades +``` + +`fail2ban` peut compléter cette base si le service SSH est exposé à Internet : + +```bash +sudo apt install fail2ban +sudo systemctl enable --now fail2ban +``` + +## Checklist du premier jour + +- [ ] système entièrement mis à jour et redémarré ; +- [ ] connexion avec un compte non-root ; +- [ ] clé Ed25519 testée dans une seconde session ; +- [ ] connexion root et mot de passe SSH désactivés ; +- [ ] configuration validée avec `sshd -t` ; +- [ ] seuls les ports 22, 80 et 443 sont ouverts ; +- [ ] mises à jour de sécurité automatiques activées ; +- [ ] accès de secours du fournisseur testé ou documenté. + +## Documentation officielle + +- [OpenSSH sur Ubuntu](https://documentation.ubuntu.com/server/how-to/security/openssh-server/) +- [Pare-feu Ubuntu](https://documentation.ubuntu.com/server/how-to/security/firewalls/) +- [Mises à jour automatiques](https://documentation.ubuntu.com/server/how-to/software/automatic-updates/) + diff --git a/content/docs/serveur/meta.json b/content/docs/serveur/meta.json new file mode 100644 index 0000000..5dd64da --- /dev/null +++ b/content/docs/serveur/meta.json @@ -0,0 +1,5 @@ +{ + "title": "Serveur", + "description": "Préparer un hôte de production fiable", + "pages": ["bien-demarrer", "preparer-docker"] +} diff --git a/content/docs/serveur/preparer-docker.mdx b/content/docs/serveur/preparer-docker.mdx new file mode 100644 index 0000000..27018c2 --- /dev/null +++ b/content/docs/serveur/preparer-docker.mdx @@ -0,0 +1,86 @@ +--- +title: Préparer l'hôte Docker +description: Installer Docker proprement et organiser le serveur pour les déploiements. +--- + +Une fois le système sécurisé, prépare un hôte minimal. Le serveur doit exécuter des images déjà construites : il n'a pas besoin du code source, de Node.js ni des outils de compilation. + +## Installer Docker depuis le dépôt officiel + +Utilise le [dépôt APT officiel de Docker](https://docs.docker.com/engine/install/ubuntu/) plutôt qu'un script d'installation téléchargé à la volée. Installe Docker Engine, le plugin Buildx et Docker Compose, puis vérifie l'installation : + +```bash +sudo systemctl enable --now docker +sudo docker run --rm hello-world +sudo docker compose version +``` + +## Choisir le bon niveau d'accès + +Ajouter un utilisateur au groupe `docker` permet d'éviter `sudo`, mais ce groupe donne des privilèges équivalents à `root`. Trois options existent : + +| Option | Usage | +| --- | --- | +| `sudo docker ...` | simple pour l'administration manuelle | +| Docker rootless | bon isolement lorsque la stack le permet | +| script de déploiement restreint | adapté à une CI qui doit lancer une seule opération | + +Évite de donner un accès Docker complet à tous les comptes. La [documentation post-installation de Docker](https://docs.docker.com/engine/install/linux-postinstall/) détaille le risque du groupe `docker` et le mode rootless. + +## Organiser les fichiers de production + +```text +/srv/mon-app/ +├── docker-compose.prod.yml +├── .env.prod +├── .env.release +└── backups/ +``` + +- `docker-compose.prod.yml` décrit les services ; +- `.env.prod` contient la configuration et les secrets du serveur ; +- `.env.release` contient uniquement le tag d'image déployé ; +- `backups/` reçoit les sauvegardes chiffrées avant leur copie hors du serveur. + +Protège les fichiers sensibles : + +```bash +sudo install -d -o root -g deploy -m 0750 /srv/mon-app +sudo install -o root -g deploy -m 0640 .env.prod /srv/mon-app/.env.prod +``` + +Les secrets ne doivent apparaître ni dans l'image, ni dans Git, ni dans les journaux de la CI. + +## Préparer le réseau et le TLS + +1. fais pointer le DNS vers l'adresse publique du serveur ; +2. expose uniquement le reverse proxy en `80` et `443` ; +3. garde la base de données et les services internes sur le réseau Docker ; +4. configure un certificat TLS avec renouvellement automatique ; +5. vérifie l'URL de santé depuis l'extérieur. + +## Prévoir l'exploitation + +Avant le premier déploiement, décide : + +- où sont stockés les volumes persistants ; +- à quelle fréquence ils sont sauvegardés ; +- comment restaurer une sauvegarde sur une machine vierge ; +- combien de temps conserver les journaux Docker ; +- qui reçoit les alertes de disponibilité et d'espace disque ; +- comment accéder au serveur si SSH ne répond plus. + + + Copie les sauvegardes hors du serveur et vérifie régulièrement qu'une restauration complète fonctionne. Un volume Docker persistant ne remplace pas une sauvegarde. + + +## Prêt pour le déploiement ? + +- [ ] Docker et Compose proviennent du dépôt officiel ; +- [ ] l'accès Docker est limité et documenté ; +- [ ] le répertoire `/srv/mon-app` est protégé ; +- [ ] les secrets sont présents uniquement sur le serveur ou dans un coffre ; +- [ ] DNS et TLS fonctionnent ; +- [ ] les volumes, sauvegardes et journaux ont une politique claire ; +- [ ] une URL de santé est disponible. +