Configurer le déploiement automatisé
Apprends à mettre en place un déploiement CI/CD avec GitHub Actions, Docker et un runner auto-hébergé pour ton projet React Router 7.
Objectif : déclencher un déploiement depuis GitHub
Dans la vidéo tu as :
- créé un runner auto-hébergé sur ton VPS ;
- poussé l’app Dockerisée sur Docker Hub ;
- configuré trois fichiers
docker-compose(dev, staging, prod) ; - écrit un workflow GitHub Actions qui
- build l’image,
- vérifie le type Script,
- déploie automatiquement en fonction de la branche.
Nous allons revoir chaque étape et comprendre la logique pour que tu puisses l’adapter à n’importe quel projet React Router 7.
1. Préparer le runner auto-hébergé
Un runner est juste un petit agent qui attend les ordres de GitHub ; dès
qu’un workflow contient runs-on: self-hosted, c’est lui qui exécute les
commandes.
1.1 Installer le binaire GitHub Runner
1# Sur ton VPS, connecté avec l'utilisateur créé précédemment2mkdir -p ~/deployments/react-router-7 && cd ~/deployments/react-router-73curl -o actions-runner-linux-x64-2.316.0.tar.gz \4-L https://github.com/actions/runner/releases/download/v2.316.0/actions-runner-linux-x64-2.316.0.tar.gz5tar xzf actions-runner-linux-x64-2.316.0.tar.gz6./config.sh # ↩️ colle ici le token fourni par GitHub
1.2 Lancer le service en tâche de fond
1sudo ./svc.sh install # installe le service systemd2sudo ./svc.sh start # démarre le runner3sudo ./svc.sh status # doit afficher Active: running
Le statut passe en idle dans l’onglet Settings → Actions → Runners de ton repo : GitHub est désormais capable de piloter ton serveur.
2. Factoriser le build Docker
Plutôt que de copier/coller la même liste de steps dans tous tes workflows,
encapsule la partie “build + push” dans un workflow réutilisable.
1name: 🐳 Build And Push Docker Image23on:4workflow_call: # 🤝 appelé depuis un autre fichier5inputs:6tag:7type: string89jobs:10build:11runs-on: ubuntu-latest12steps:13- uses: actions/checkout@v414- uses: docker/login-action@v215with:16username: ${{ secrets.DOCKERHUB_USERNAME }}17password: ${{ secrets.DOCKERHUB_TOKEN }}1819- uses: docker/setup-buildx-action@v2 # build multi-arch20- name: Build ${{ inputs.tag }}21uses: docker/build-push-action@v322with:23context: .24push: true25tags: algomax/react-router-7:${{ inputs.tag }}
3. La CI : type-check + build
1name: Docker Image CI23on:4push:5branches: ["main", "dev"]6pull_request:7branches: ["main", "dev"]89jobs:10build:11name: 🐳 build12uses: ./.github/workflows/build.yml13with:14tag: ${{ github.ref == 'refs/heads/main' && 'production' || 'latest' }}15secrets: inherit # ↩️ transmet DOCKERHUB_* au sous-workflow1617typecheck:18runs-on: ubuntu-latest19steps:20- uses: actions/checkout@v421- name: Install deps22run: npm ci23- name: TypeScript strict24run: npm run typecheck
Tip
Un deuxième job isolé évite de reconstruire l’image si le typecheck plante : gagne du temps et des crédits GitHub.
4. Déploiement automatisé sur le VPS
1deploy:2name: 🚀 Deploy3runs-on: [self-hosted] # ⬅️ notre runner VPS4needs: [build, typecheck]5if: ${{ github.event_name == 'push' }}6env: # variables communes7SMTP_USER: ${{ secrets.SMTP_USER }}8SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}9SMTP_PORT: ${{ secrets.SMTP_PORT }}10SMTP_SENDER: ${{ secrets.SMTP_SENDER }}11SMTP_HOST: ${{ secrets.SMTP_HOST }}1213steps:14- uses: actions/checkout@v415- uses: docker/login-action@v216with:17username: ${{ secrets.DOCKERHUB_USERNAME }}18password: ${{ secrets.DOCKERHUB_TOKEN }}1920- name: 🏗️ Pull & run – staging21if: github.ref == 'refs/heads/dev'22env:23FRONTEND_URL: ${{ secrets.FRONTEND_URL_STAGING }}24DATABASE_URL: ${{ secrets.DATABASE_URL_STAGING }}25run: |26docker pull algomax/react-router-7:latest27docker compose -f docker-compose.staging.yml up -d28docker system prune --all --volumes --force2930- name: 🏗️ Pull & run – production31if: github.ref == 'refs/heads/main'32env:33FRONTEND_URL: ${{ secrets.FRONTEND_URL }}34DATABASE_URL: ${{ secrets.DATABASE_URL }}35run: |36docker pull algomax/react-router-7:production37docker compose -f docker-compose.prod.yml up -d38docker system prune --all --volumes --force
- Deux environnements :
–
devpousse sur l’imagelatest, exposée port3010; –mainpousse surproduction, exposée port3000. docker system prunegarde le VPS propre (images et volumes obsolètes).
Warning
Assure-toi que les ports ne se chevauchent pas : 3000 pour prod, 3010 pour
staging dans les fichiers docker-compose.
5. Les fichiers docker-compose
1services:2react_router_production:3image: algomax/react-router-7:production4container_name: react_router_production5env_file: .env.production # Secrets montés à part6restart: always7ports:8- "3000:3000"
1services:2react_router_staging:3image: algomax/react-router-7:latest4container_name: react_router_staging5env_file: .env.staging6restart: always7ports:8- "3010:3000"
6. Secrets & variables GitHub
- Settings → Secrets and variables → Actions
- Ajoute :
DOCKERHUB_USERNAME,DOCKERHUB_TOKEN,SMTP_*,FRONTEND_URL,DATABASE_URL, etc. - Les secrets sont injectés dans le workflow
via
${{ secrets.MA_VARIABLE }}.
Caution
Ne stocke jamais un mot de passe dans le dépôt ; si tu bosses à plusieurs, limite la visibilité des secrets au repo.
7. Cycle complet d’une mise en production
1flowchart LR2dev[Dev push] -->|branch dev| ci(Build+Type) --> VPSStaging3main[Merge → main] -->|branch main| ci2(Build+Type) --> VPSProd
- Push sur
dev➜ imagelatest, déploiement staging (port 3010). - Merge vers
main➜ imageproduction, déploiement prod (port 3000). - Les deux conteneurs co-habitent, redémarrables à la commande :
1docker restart react_router_staging2docker restart react_router_production
8. Tester en local : le mode développeur
1# Porte 3000, rebuild sur chaque changement2docker compose -f docker-compose.dev.yml up --build
La version dev utilise le Dockerfile pour conserver le hot-reload tandis que staging/prod tirent l’image déjà buildée.
9. Nommage et bonne pratique Docker
- Nom de conteneur explicite (
react_router_staging) => auto-complétiondocker stop rea<Tab>. - Redémarrage avec
docker restart, pas besoin de rejouer la CI. - Prune régulier des images obsolètes :
1docker system prune --all --volumes
10. Prochaine étape : le reverse proxy HTTPS
Le site répond déjà sur :3000 via l’adresse IP, mais un vrai domaine
exigera :
- un enregistrement A vers l’IP VPS ;
- Caddy (ou Nginx) pour gérer TLS et rediriger
https://rr7.algomax.fr➜http://localhost:3000.
Nous détaillons ça dans la leçon suivante.
Important
Ta CI est prête, tes images sont publiées, le VPS exécute staging & prod
— tu viens de franchir 90 % du chemin vers un déploiement pro !
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?