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.
avec React Router 7
Posez vos questions 24/7 à notre IA experte en React Router 7
Validez vos acquis avec des quiz personnalisés et un feedback instantané
Dans la vidéo tu as :
docker-compose
(dev, staging, prod) ;Nous allons revoir chaque étape et comprendre la logique pour que tu puisses l’adapter à n’importe quel projet React Router 7.
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# 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
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.
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 }}
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
Un deuxième job isolé évite de reconstruire l’image si le typecheck plante : gagne du temps et des crédits GitHub.
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
dev
pousse sur l’image latest
, exposée port 3010
;
– main
pousse sur production
, exposée port 3000
.docker system prune
garde le VPS propre (images et volumes obsolètes).Assure-toi que les ports ne se chevauchent pas : 3000 pour prod, 3010 pour
staging dans les fichiers docker-compose
.
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"
DOCKERHUB_USERNAME
, DOCKERHUB_TOKEN
, SMTP_*
,
FRONTEND_URL
, DATABASE_URL
, etc.${{ secrets.MA_VARIABLE }}
.Ne stocke jamais un mot de passe dans le dépôt ; si tu bosses à plusieurs, limite la visibilité des secrets au repo.
1flowchart LR2dev[Dev push] -->|branch dev| ci(Build+Type) --> VPSStaging3main[Merge → main] -->|branch main| ci2(Build+Type) --> VPSProd
dev
➜ image latest
, déploiement staging (port 3010).main
➜ image production
, déploiement prod (port 3000).1docker restart react_router_staging2docker restart react_router_production
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.
react_router_staging
) => auto-complétion
docker stop rea<Tab>
.docker restart
, pas besoin de rejouer la CI.1docker system prune --all --volumes
Le site répond déjà sur :3000
via l’adresse IP, mais un vrai domaine
exigera :
https://rr7.algomax.fr
➜ http://localhost:3000
.Nous détaillons ça dans la leçon suivante.
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 !
Quelle est la principale différence entre les composants client et serveur dans React ?
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Quel hook permet de gérer les effets de bord dans un composant React ?
Comment implémenter la gestion des erreurs pour les requêtes API dans React ?
Quelle est la meilleure pratique pour déployer une application React en production ?