Ce qu'il faut retenir
Un pipeline CI/CD GitHub Actions pour Next.js B2B se décompose en quatre phases : vérification statique (lint, type-check), tests unitaires et E2E Playwright avec sharding, déploiement conditionnel (Vercel preview ou production, OVH/AWS via Docker), puis monitoring post-déploiement avec rollback automatique.
Le cache GitHub Actions combiné au remote caching Turborepo permet de réduire les temps de pipeline de 70 à 85% sur les projets de taille significative — la différence entre 14 minutes et 2 minutes 30 pour une PR classique.
La sécurité dans le pipeline ne se limite pas à stocker les secrets dans GitHub Secrets : SAST automatisé (CodeQL ou Semgrep), SBOM généré à chaque build, Dependabot configuré par ecosystem, et rotation des tokens de déploiement sont des pratiques non négociables sur un projet B2B en production.
CI/CD GitHub Actions Next.js 2026 : pipeline de déploiement complet
Par Chokri Siala, CTO Nehos — lint, type-check, Playwright E2E shardé, déploiement Vercel et OVH, secrets SAST, cache Turborepo. Le pipeline production-ready que nous appliquons sur tous nos projets B2B.
Adapté à toute taille de structure
#Pourquoi un pipeline CI/CD est indispensable pour les projets Next.js B2B
En 2026, livrer un projet Next.js sans pipeline CI/CD est aussi risqué que de déployer en production sans tests. Pourtant, dans les projets B2B que nous auditons chez Nehos, un tiers arrivent encore avec des déploiements manuels : git pull && npm run build && pm2 restart sur le serveur. La dette technique qui s'accumule autour de cette pratique est considérable.
Les enjeux d'un pipeline CI/CD pour Next.js en contexte B2B vont bien au-delà de l'automatisation du déploiement. Ils touchent à la qualité du code (lint, type-check, tests automatisés à chaque PR), à la sécurité (détection des vulnérabilités avant production), à la vélocité de l'équipe (feedback en 3 minutes plutôt que 45), et à la confiance des parties prenantes (chaque déploiement est tracé, réversible, documenté).
Les chiffres parlent d'eux-mêmes sur nos projets B2B Next.js :
- Réduction des bugs en production : -62% sur les 3 mois suivant la mise en place d'un pipeline complet
- Temps de détection d'une régression : de 2-3 jours (détection manuelle) à moins de 8 minutes (pipeline automatisé)
- Fréquence de déploiement : ×4 après mise en place du CI/CD (le frein psychologique du déploiement manuel disparaît)
- Temps de rollback : de 25-40 minutes (rollback manuel) à moins de 90 secondes (rollback automatisé)
Ce guide présente le pipeline exact que nous déployons sur les projets Next.js B2B premium chez Nehos — avec les fichiers YAML complets, les justifications de chaque choix, et les pièges à éviter.
#GitHub Actions : concepts clés, workflows, runners, secrets
Avant de présenter le pipeline, un rappel des concepts fondamentaux de GitHub Actions que nous utilisons systématiquement.
#Workflows, jobs et steps
Un workflow est un fichier YAML dans .github/workflows/. Il contient un ou plusieurs jobs, qui s'exécutent en parallèle par défaut (ou en séquence si needs: est déclaré). Chaque job contient des steps : commandes shell ou actions réutilisables.
Nous structurons systématiquement nos workflows en trois fichiers séparés :
.github/workflows/ci.yml: lint, type-check, tests — déclenché sur chaque PR et push surmain.github/workflows/deploy-preview.yml: déploiement preview — déclenché sur chaque PR.github/workflows/deploy-production.yml: déploiement production — déclenché uniquement sur merge dansmain
Cette séparation permet de voir en un coup d'œil ce qui a échoué, et de ré-exécuter uniquement la phase concernée sans relancer tout le pipeline.
#Runners : ubuntu-latest vs self-hosted
Pour la majorité des projets B2B Next.js, les runners hébergés GitHub (ubuntu-latest) sont suffisants. Ils coûtent 0,008 $ par minute pour les dépôts privés. Sur un projet avec 20 PRs/semaine et un pipeline de 6 minutes, le coût mensuel est inférieur à à partir de 960 €.
Les runners self-hosted deviennent pertinents dans deux cas : contraintes de souveraineté (le code ne doit pas quitter l'infrastructure de l'entreprise) ou besoins de performances exceptionnelles (builds très longs sur des monorepos de grande taille). Pour les projets sur cloud souverain OVH, nous configurons des runners auto-hébergés sur des instances OVH.
#Secrets et variables d'environnement
GitHub Actions distingue trois niveaux de secrets :
- Repository secrets : accessibles à tous les workflows du repo
- Environment secrets : accessibles uniquement aux workflows associés à un environment (
staging,production) - Organization secrets : partagés entre plusieurs repos de l'organisation
Bonne pratique absolue : les tokens de déploiement production (VERCEL_TOKEN, KUBECONFIG, OVH_APPLICATION_KEY) doivent être des environment secrets avec protection de branche — ils ne sont accessibles qu'après approbation manuelle d'un reviewer désigné.
# Exemple de protection d'environment dans le workflow
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: production # Déclenche la règle d'approbation
steps:
- name: Deploy to Vercel Production
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Secret d'environment
run: vercel --prod --token $VERCEL_TOKEN
#Pipeline de base : lint, type-check, tests unitaires, build Next.js
Voici le workflow CI complet que nous utilisons comme base sur tous nos projets Next.js B2B.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ci:
name: Lint, Type-check, Tests, Build
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Nécessaire pour Turborepo affected
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm turbo lint --filter='...[origin/main]'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Type-check
run: pnpm turbo typecheck --filter='...[origin/main]'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Unit tests
run: pnpm turbo test --filter='...[origin/main]'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Build
run: pnpm turbo build --filter='...[origin/main]'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
NEXT_PUBLIC_API_URL: ${{ vars.NEXT_PUBLIC_API_URL_STAGING }}
- name: Upload coverage
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-reports
path: '**/coverage/**'
retention-days: 7
#La directive cancel-in-progress: true
La directive concurrency avec cancel-in-progress: true annule automatiquement le run précédent quand un nouveau push arrive sur la même branche. Sur une PR active avec plusieurs commits rapprochés, cela évite de faire tourner 5 pipelines en parallèle et de saturer les minutes GitHub Actions.
#Le --filter='...[origin/main]'
Combinée avec le remote caching Turborepo, la syntaxe --filter='...[origin/main]' ne traite que les packages modifiés depuis main et leurs dépendants. Sur un monorepo avec 3 apps et 8 packages, une PR qui touche uniquement l'app marketing ne relancera pas le build et les tests de portail-client et back-office. Ce seul paramètre explique une large part des gains de performance CI mesurés sur nos projets Turborepo monorepo.
#Tests E2E avec Playwright en CI : sharding, cache, rapports
Playwright est l'outil de référence pour les tests E2E en 2026 — son support natif des navigateurs modernes, la génération de code, et surtout le sharding natif en font le choix évident pour les pipelines CI à fort volume de tests. Nous avons détaillé les raisons de ce choix dans notre comparatif Playwright vs Cypress.
#Sharding : paralléliser les tests sur plusieurs runners
Le sharding Playwright divise la suite de tests en N fragments exécutés en parallèle sur N runners GitHub Actions. Sur 200 tests E2E qui prenaient 22 minutes en séquence, le sharding sur 4 runners les ramène à 6 minutes.
# .github/workflows/e2e.yml
name: E2E Tests
on:
pull_request:
branches: [main]
jobs:
e2e:
name: Playwright E2E (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium
- name: Build app for E2E
run: pnpm turbo build --filter=marketing
env:
NEXT_PUBLIC_API_URL: ${{ vars.NEXT_PUBLIC_API_URL_STAGING }}
- name: Run Playwright tests (shard)
run: pnpm exec playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
BASE_URL: http://localhost:3000
CI: true
- name: Upload blob report
uses: actions/upload-artifact@v4
if: always()
with:
name: blob-report-${{ matrix.shardIndex }}
path: playwright-report/
retention-days: 1
merge-reports:
name: Merge Playwright Reports
runs-on: ubuntu-latest
needs: e2e
if: always()
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge reports
run: npx playwright merge-reports --reporter=html ./all-blob-reports
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 14
#Cache des navigateurs Playwright
L'installation des navigateurs Playwright prend 1 à 2 minutes. Pour l'éviter à chaque run, on cache le répertoire des navigateurs :
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml') }}
restore-keys: |
playwright-${{ runner.os }}-
Ce cache économise 90 à 120 secondes par run — sur 60 PRs par mois, c'est 1 à 2 heures de CI économisées. La qualité du code et les standards automatisés passent par ce genre d'optimisation incrémentale.
#Déploiement sur Vercel via GitHub Actions : preview + production
Vercel est la plateforme de déploiement de référence pour Next.js, et son intégration GitHub Actions est mature. Nous distinguons deux workflows : preview (pour les PRs) et production (pour les merges sur main).
#Déploiement preview sur chaque PR
# .github/workflows/deploy-preview.yml
name: Deploy Preview
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy-preview:
name: Deploy to Vercel Preview
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel environment
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build project
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Deploy to Vercel Preview
id: deploy
run: |
DEPLOY_URL=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
echo "deploy_url=$DEPLOY_URL" >> $GITHUB_OUTPUT
- name: Comment PR with preview URL
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `**Preview prête** : ${{ steps.deploy.outputs.deploy_url }}\n\nDéployée depuis le commit \`${{ github.sha }}\`.`
})
#Déploiement production avec approbation obligatoire
# .github/workflows/deploy-production.yml
name: Deploy Production
on:
push:
branches: [main]
jobs:
deploy-production:
name: Deploy to Vercel Production
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Install Vercel CLI
run: npm install --global vercel@latest
- name: Pull Vercel environment
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build project
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Deploy to Vercel Production
id: deploy
run: |
DEPLOY_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})
echo "deploy_url=$DEPLOY_URL" >> $GITHUB_OUTPUT
- name: Notify Slack
uses: slackapi/slack-github-action@v2
with:
payload: |
{"text": "Production déployée : ${{ steps.deploy.outputs.deploy_url }} (commit ${{ github.sha }})"}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
L'environment: production dans le job déclenche la règle de protection configurée dans les paramètres GitHub : au moins un reviewer désigné doit approuver manuellement avant que le déploiement production ne démarre. Cette mécanique est le filet de sécurité minimal pour tout projet B2B en production.
→ Vous évaluez vos options ? Utilisez notre estimateur de budget en ligne pour obtenir une fourchette en 2 minutes, ou consultez nos tarifs détaillés.
#Déploiement OVHcloud/AWS : artefacts Docker, Kubernetes manifests
Pour les projets qui ne peuvent pas ou ne veulent pas utiliser Vercel — souvent pour des raisons de souveraineté, de coût à grande échelle, ou d'exigences infrastructure spécifiques — nous déployons sur microservices Kubernetes hébergés sur OVHcloud ou AWS EKS.
#Build et push de l'image Docker
# Extrait de .github/workflows/deploy-production.yml (variante Kubernetes)
jobs:
build-and-push:
name: Build Docker image and push
runs-on: ubuntu-latest
environment: production
outputs:
image_tag: ${{ steps.meta.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to OVH registry
uses: docker/login-action@v3
with:
registry: ${{ vars.OVH_REGISTRY_URL }}
username: ${{ secrets.OVH_REGISTRY_USER }}
password: ${{ secrets.OVH_REGISTRY_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ vars.OVH_REGISTRY_URL }}/nehos/app-marketing
tags: |
type=sha,prefix=,suffix=,format=short
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./apps/marketing/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL_PROD }}
#Dockerfile optimisé pour Next.js
Le Dockerfile multi-stage qui réduit l'image finale de 1,2 Go à environ 180 Mo :
# Dockerfile (multi-stage)
FROM node:22-alpine AS base
RUN corepack enable
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/marketing/package.json ./apps/marketing/
COPY packages/ ./packages/
RUN pnpm install --frozen-lockfile
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm turbo build --filter=marketing
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/apps/marketing/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/marketing/.next/static ./apps/marketing/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/marketing/public ./apps/marketing/public
USER nextjs
EXPOSE 3000
CMD ["node", "apps/marketing/server.js"]
#Déploiement sur Kubernetes avec rollout
deploy-kubernetes:
name: Deploy to Kubernetes (OVH)
runs-on: ubuntu-latest
needs: build-and-push
environment: production
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure kubectl
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBECONFIG_OVH_PROD }}
- name: Update image tag in manifest
run: |
sed -i "s|IMAGE_TAG|${{ needs.build-and-push.outputs.image_tag }}|g" \
k8s/marketing-deployment.yaml
- name: Apply Kubernetes manifests
run: kubectl apply -f k8s/marketing-deployment.yaml
- name: Wait for rollout
run: kubectl rollout status deployment/marketing --timeout=300s
#Sécurité dans le pipeline : secrets management, SAST, SBOM, Dependabot
La sécurité d'un pipeline CI/CD est un sujet à part entière — et souvent le parent pauvre des projets. Nous appliquons systématiquement les recommandations OWASP DevSecOps sur tous nos pipelines.
#SAST avec CodeQL
CodeQL est l'outil d'analyse statique de sécurité natif de GitHub. Il analyse le code TypeScript/JavaScript à la recherche de vulnérabilités connues (injections, XSS, mauvaise gestion des secrets) à chaque PR.
# .github/workflows/security.yml
name: Security Analysis
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * 1' # Chaque lundi à 2h
jobs:
codeql:
name: CodeQL Analysis
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:javascript-typescript
#Génération du SBOM à chaque build
Le Software Bill of Materials (SBOM) est un inventaire de toutes les dépendances de l'application. Il est requis par le DORA Act et les nouvelles exigences de conformité pour les applications B2B traitant des données sensibles.
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
path: .
format: spdx-json
output-file: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom-${{ github.sha }}
path: sbom.spdx.json
retention-days: 90
#Dependabot : mises à jour automatiques par ecosystem
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: '09:00'
timezone: Europe/Paris
groups:
nextjs-ecosystem:
patterns: ["next", "react", "react-dom", "@types/react*"]
testing:
patterns: ["@playwright/test", "vitest", "@testing-library*"]
open-pull-requests-limit: 10
- package-ecosystem: docker
directory: /
schedule:
interval: weekly
#Rotation automatique des tokens
Les tokens de déploiement (Vercel, Docker registry, Kubernetes) doivent être rotés régulièrement. Nous configurons des alertes GitHub Actions qui déclenchent une notification Slack 7 jours avant l'expiration d'un secret (pour les secrets avec date d'expiration configurée). Pour les tokens sans expiration, une rotation trimestrielle est planifiée dans le calendrier d'équipe — et documentée dans le runbook du projet.
#Cache et optimisation : GitHub Actions cache, remote caching Turborepo
Un pipeline CI/CD lent est un pipeline que les développeurs évitent ou ignorent. L'optimisation du cache est la première étape pour rendre le CI agréable à utiliser. La combinaison Turborepo remote caching + cache GitHub Actions peut réduire les temps de pipeline de 70 à 85%.
#Stratégie de cache multicouche
# Couche 1 : dépendances pnpm
- name: Setup Node.js avec cache pnpm
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm # Cache automatique via setup-node
# Couche 2 : navigateurs Playwright
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: playwright-${{ runner.os }}-
# Couche 3 : cache Docker layers (via buildx)
- name: Build and push (avec cache GHA)
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
# Couche 4 : remote caching Turborepo
# Activé via TURBO_TOKEN + TURBO_TEAM sur toutes les commandes turbo
#Remote caching Turborepo : configuration complète
Le remote caching Turborepo stocke les artefacts de build (résultats de lint, type-check, test, build) sur des serveurs distants. Quand un autre développeur ou un autre runner CI exécute la même tâche sur le même code, Turborepo restaure le résultat depuis le cache au lieu de réexécuter la tâche.
# Configuration initiale (une seule fois)
npx turbo login
npx turbo link
# Variables d'environnement CI nécessaires
# TURBO_TOKEN : token d'accès Vercel ou self-hosted cache
# TURBO_TEAM : identifiant de l'équipe (ex: "nehos")
# TURBO_API : URL du cache si self-hosted (sinon Vercel par défaut)
#Self-hosted cache avec OVH Object Storage
Pour les projets avec exigences de souveraineté, nous déployons turborepo-remote-cache sur OVH :
# Configuration turbo.json pour self-hosted cache
# Dans la commande CI :
# TURBO_API=https://cache.votre-domaine.com
# TURBO_TOKEN=votre-token-self-hosted
Le serveur turborepo-remote-cache est compatible avec l'API S3 d'OVH Object Storage. La mise en place prend moins d'une heure, et les performances sont comparables au cache Vercel pour les projets hébergés en Europe.
#Mesures de performance sur nos projets B2B
| Phase du pipeline | Sans cache | Avec cache (premier run) | Avec cache (run suivant) |
|---|---|---|---|
pnpm install | 3 min 20s | 45s (cache dépendances) | 45s |
turbo lint | 2 min 10s | 2 min 10s (cold) | 8s (remote cache) |
turbo typecheck | 1 min 50s | 1 min 50s (cold) | 6s (remote cache) |
turbo build | 5 min 40s | 5 min 40s (cold) | 55s (remote cache) |
| Playwright (4 shards) | 22 min | 6 min (sharding) | 6 min |
| Total pipeline | ~35 min | ~16 min | ~8 min |
Le gain de 35 minutes à 8 minutes n'est pas uniquement lié au cache — c'est la combinaison du sharding Playwright, du cache des dépendances, et du remote caching Turborepo. La productivité des développeurs est directement corrélée à la vitesse du feedback CI.
#Monitoring post-déploiement : alertes, rollback automatique
Un pipeline CI/CD ne s'arrête pas au déploiement. Le monitoring post-déploiement — et la capacité à revenir en arrière rapidement en cas de problème — est la dernière couche d'un pipeline mature.
#Health check post-déploiement
- name: Health check post-deploy
run: |
echo "Waiting for deployment to stabilize..."
for i in {1..12}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://votre-app.com/api/health)
if [ "$STATUS" = "200" ]; then
echo "Health check OK (attempt $i)"
exit 0
fi
echo "Health check failed (attempt $i, status $STATUS), retrying in 10s..."
sleep 10
done
echo "Health check failed after 12 attempts"
exit 1
#Rollback automatique sur Vercel
Vercel conserve les 10 derniers déploiements accessibles instantanément. En cas d'échec du health check, le rollback se fait via l'API Vercel :
- name: Rollback on failure
if: failure()
run: |
PREVIOUS_DEPLOYMENT=$(vercel ls --token=${{ secrets.VERCEL_TOKEN }} \
--json | jq -r '.[1].uid')
vercel rollback $PREVIOUS_DEPLOYMENT \
--token=${{ secrets.VERCEL_TOKEN }}
echo "Rolled back to deployment: $PREVIOUS_DEPLOYMENT"
#Rollback sur Kubernetes
Sur un cluster Kubernetes, le rollback utilise la commande native kubectl rollout undo :
- name: Rollback Kubernetes deployment
if: failure()
run: |
kubectl rollout undo deployment/marketing
kubectl rollout status deployment/marketing --timeout=120s
echo "Rollback completed"
#Alertes Slack et PagerDuty
Nous configurons systématiquement des alertes sur trois niveaux :
- Alerte pipeline : notification Slack sur chaque échec CI/CD (webhook Slack ou action
slackapi/slack-github-action) - Alerte déploiement : notification Slack + PagerDuty sur échec de déploiement production
- Alerte monitoring continu : via Core Web Vitals et alertes Vercel Analytics — dégradation de performance post-déploiement détectée en moins de 5 minutes
- name: Alert on failure
if: failure()
uses: slackapi/slack-github-action@v2
with:
payload: |
{
"text": ":red_circle: Pipeline échoué sur `${{ github.repository }}` — branche `${{ github.ref_name }}`",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Échec* : <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Voir le run CI>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
#Métriques DORA dans le pipeline
Les métriques DORA (Deployment Frequency, Lead Time for Changes, Change Failure Rate, Time to Restore Service) peuvent être calculées automatiquement en exploitant les événements GitHub Actions. Nous utilisons un job dédié qui alimente un dashboard interne après chaque déploiement production réussi — donnant aux équipes une visibilité en temps réel sur leur maturité DevOps. La refonte B2B avec Nehos inclut systématiquement la mise en place de ces métriques.