Général 15 min de lecture · 3 163 mots

Pipelines CI/CD en 2025 : GitHub Actions, GitLab CI et Jenkins

Guide complet des pipelines CI/CD en 2025 : comparaison GitHub Actions, GitLab CI et Jenkins avec meilleures pratiques et exemples concrets.

Pipelines CI/CD en 2025 : GitHub Actions, GitLab CI et Jenkins
Général · 2025.12.19

L’intégration continue et le déploiement continu (CI/CD) sont devenus le cœur battant du développement logiciel moderne. En 2025, le paysage des outils CI/CD a considérablement évolué, avec GitHub Actions et GitLab CI qui gagnent du terrain face à Jenkins, le vétéran du domaine. Ce guide complet vous aide à choisir le bon outil et à implémenter des pipelines robustes et efficaces.

État des Lieux CI/CD en 2025

Selon l’enquête JetBrains 2025, de nombreuses entreprises utilisent encore des produits hérités comme Azure DevOps ou Jenkins tout en migrant vers GitHub Actions ou GitLab CI, parfois sur des périodes de plusieurs mois ou années.

Tendances principales :

  • Migration massive : Des équipes quittent Jenkins pour GitHub Actions/GitLab CI
  • Conteneurs partout : Pipelines qui construisent, testent et déploient des images Docker
  • GitOps : Pipelines déclaratifs versionnés avec le code
  • AI-driven testing : Tests automatisés optimisés par IA
  • Sécurité intégrée : SAST, DAST et scanning de dépendances par défaut
  • Comparaison des Outils CI/CD

    Guide de Sélection

    Pour les startups utilisant GitHub, GitHub Actions est la solution la plus simple. Pour les grandes entreprises avec des systèmes legacy, Jenkins offre une flexibilité maximale. Pour les équipes entièrement sur GitLab, GitLab CI/CD est le meilleur choix.

    Tableau Comparatif

    Critère GitHub Actions GitLab CI Jenkins
    Hébergement Cloud (gratuit/payant) Cloud ou Self-hosted Self-hosted
    Configuration YAML (.github/workflows/) YAML (.gitlab-ci.yml) Jenkinsfile ou UI
    Marketplace 20,000+ actions Limité 1,800+ plugins
    Intégration Native GitHub Native GitLab Plugins requis
    Coût startup Gratuit (2000 min/mois) Gratuit (400 min/mois) Infrastructure uniquement
    Courbe d’apprentissage Facile Facile Moyenne/Élevée
    Sécurité Secrets managés SAST/DAST intégrés Plugins requis

    GitHub Actions : La Simplicité au Service de GitHub

    GitHub Actions est intégré directement dans GitHub, utilisant des fichiers de workflow basés sur YAML stockés dans le repository, permettant des configurations de pipeline versionnées.

    Caractéristiques Clés

  • Intégration transparente avec les repositories GitHub
  • Marketplace : Accès à des milliers d’actions pré-construites
  • Event-driven : Workflows déclenchés sur push, pull requests, webhooks personnalisés
  • Matrix builds : Tester sur plusieurs versions/environnements simultanément
  • Runners : Hébergés (Linux, Windows, macOS) ou self-hosted
  • Migration depuis Jenkins

    Les équipes ayant migré de Jenkins self-hosted vers GitHub Actions rapportent : « Way easier to maintain. Way easier to implement your pipelines. » (Source: JetBrains Survey 2025)

    Exemple de Workflow GitHub Actions

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '20'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # Job 1: Tests et Linting
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 21]

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run tests
        run: npm test -- --coverage

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage/lcov.info

  # Job 2: Security Scan
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-results.sarif'

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

  # Job 3: Build et Push Docker
  build:
    needs: [test, security]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=sha,prefix={{branch}}-
            type=semver,pattern={{version}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max

  # Job 4: Deploy (SSH + Docker Compose)
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Deploy over SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.DEPLOY_SSH_KEY }}
          script: |
            cd /opt/myapp
            export IMAGE_TAG=${{ github.sha }}
            docker compose pull
            docker compose up -d
            docker compose ps

      - name: Notify Slack
        if: always()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          text: 'Deployment to production: ${{ job.status }}'
          webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Fonctionnalités Avancées

Actions réutilisables :

# .github/workflows/reusable-build.yml
name: Reusable Build Workflow

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      docker-username:
        required: true
      docker-password:
        required: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build for ${{ inputs.environment }}
        run: npm run build:${{ inputs.environment }}
# Utilisation dans un autre workflow
jobs:
  build-prod:
    uses: ./.github/workflows/reusable-build.yml
    with:
      environment: production
    secrets:
      docker-username: ${{ secrets.DOCKER_USERNAME }}
      docker-password: ${{ secrets.DOCKER_PASSWORD }}

GitLab CI/CD : Plateforme DevOps Complète

GitLab est une plateforme DevOps complète, avec le CI/CD intégré comme l’une de ses fonctionnalités les plus puissantes. GitLab utilise un seul fichier déclaratif (.gitlab-ci.yml) pour définir l’ensemble du cycle de vie du développement logiciel, offrant une transparence, une auditabilité et une facilité de maintenance inégalées.

Caractéristiques Distinctives

  • DevSecOps intégré : SAST, DAST, dependency scanning par défaut
  • Environnements intégrés : Suivi des déploiements staging et production
  • Review Apps : Environnements éphémères pour chaque MR
  • Pipeline as Code : Fichier unique .gitlab-ci.yml
  • Excellence Sécurité

    GitLab excelle dans l’intégration de la sécurité, avec des jobs pré-configurés pour les tests de sécurité SAST et DAST.

    Exemple Complet GitLab CI

    # .gitlab-ci.yml
    stages:
      - build
      - test
      - security
      - deploy
    
    variables:
      DOCKER_DRIVER: overlay2
      DOCKER_TLS_CERTDIR: "/certs"
      REGISTRY_IMAGE: $CI_REGISTRY_IMAGE
    
    # Template pour build Docker
    .docker-build:
      image: docker:24-dind
      services:
        - docker:24-dind
      before_script:
        - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    
    # Job : Build Application
    build:
      extends: .docker-build
      stage: build
      script:
        - docker build
            --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
            --build-arg VCS_REF=$CI_COMMIT_SHORT_SHA
            --cache-from $REGISTRY_IMAGE:latest
            -t $REGISTRY_IMAGE:$CI_COMMIT_SHA
            -t $REGISTRY_IMAGE:latest
            .
        - docker push $REGISTRY_IMAGE:$CI_COMMIT_SHA
        - docker push $REGISTRY_IMAGE:latest
      only:
        - branches
    
    # Job : Tests Unitaires
    unit-tests:
      stage: test
      image: node:20-alpine
      cache:
        key: ${CI_COMMIT_REF_SLUG}
        paths:
          - node_modules/
      script:
        - npm ci
        - npm run test:unit -- --coverage
      coverage: '/Statementss*:s*(d+.d+)%/'
      artifacts:
        reports:
          coverage_report:
            coverage_format: cobertura
            path: coverage/cobertura-coverage.xml
        paths:
          - coverage/
    
    # Job : Tests d'Intégration
    integration-tests:
      stage: test
      image: $REGISTRY_IMAGE:$CI_COMMIT_SHA
      services:
        - name: postgres:16-alpine
          alias: database
        - name: redis:7-alpine
          alias: cache
      variables:
        DATABASE_URL: "postgresql://user:pass@database:5432/testdb"
        REDIS_URL: "redis://cache:6379"
      script:
        - npm run test:integration
      only:
        - merge_requests
        - main
    
    # Job : SAST (Static Application Security Testing)
    sast:
      stage: security
      include:
        - template: Security/SAST.gitlab-ci.yml
    
    # Job : Dependency Scanning
    dependency_scanning:
      stage: security
      include:
        - template: Security/Dependency-Scanning.gitlab-ci.yml
    
    # Job : Container Scanning
    container_scanning:
      stage: security
      image: registry.gitlab.com/security-products/container-scanning:latest
      variables:
        CI_APPLICATION_REPOSITORY: $REGISTRY_IMAGE
        CI_APPLICATION_TAG: $CI_COMMIT_SHA
      script:
        - gtcs scan
      artifacts:
        reports:
          container_scanning: gl-container-scanning-report.json
      only:
        - main
    
    # Modèle : connexion SSH au serveur de déploiement
    .ssh-setup:
      image: alpine:3.20
      before_script:
        - apk add --no-cache openssh-client
        - eval $(ssh-agent -s)
        - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
        - mkdir -p ~/.ssh && chmod 700 ~/.ssh
        - ssh-keyscan "$DEPLOY_HOST" >> ~/.ssh/known_hosts
    
    # Job : Deploy to Staging
    deploy:staging:
      extends: .ssh-setup
      stage: deploy
      environment:
        name: staging
        url: https://staging.monapp.com
        on_stop: stop:staging
      script:
        - ssh "$DEPLOY_USER@$DEPLOY_HOST" "cd /opt/myapp-staging && IMAGE_TAG=$CI_COMMIT_SHA docker compose pull && IMAGE_TAG=$CI_COMMIT_SHA docker compose up -d"
      only:
        - main
    
    # Job : Deploy to Production
    deploy:production:
      extends: .ssh-setup
      stage: deploy
      environment:
        name: production
        url: https://monapp.com
      script:
        - ssh "$DEPLOY_USER@$DEPLOY_HOST" "cd /opt/myapp && IMAGE_TAG=$CI_COMMIT_SHA docker compose pull && IMAGE_TAG=$CI_COMMIT_SHA docker compose up -d"
      when: manual  # Déploiement manuel requis
      only:
        - main
    
    # Job : Arrêt environnement staging
    stop:staging:
      extends: .ssh-setup
      stage: deploy
      environment:
        name: staging
        action: stop
      script:
        - ssh "$DEPLOY_USER@$DEPLOY_HOST" "cd /opt/myapp-staging && docker compose down"
      when: manual
      only:
        - main
    

    Jenkins : Flexibilité et Puissance

    Jenkins est l’un des outils CI/CD les plus anciens et les plus utilisés, un serveur d’automatisation open-source qui aide à automatiser la construction, le test et le déploiement des applications. Il utilise des plugins pour s’intégrer avec quasiment toutes les technologies : Docker, AWS, GitHub, Slack, etc.

    Pourquoi Jenkins Reste Pertinent

  • Écosystème de plugins : 1,800+ plugins pour tout intégrer
  • Flexibilité totale : Scriptable en Groovy (Jenkinsfile)
  • Legacy support : Parfait pour les systèmes existants
  • Communauté massive : Des années de connaissance accumulée
  • Inconvénients

    Cependant, des outils comme Jenkins nécessitent une configuration significative, donc les services managés comme GitHub Actions ou GitLab CI offrent des configurations plus simples.

    Exemple Jenkinsfile Moderne

    // Jenkinsfile déclaratif
    pipeline {
        agent any
    
        environment {
            DOCKER_REGISTRY = 'docker.io'
            DOCKER_CREDENTIALS = credentials('docker-hub-credentials')
            IMAGE_NAME = "monentreprise/monapp"
            GIT_COMMIT_SHORT = sh(
                returnStdout: true,
                script: 'git rev-parse --short HEAD'
            ).trim()
        }
    
        options {
            buildDiscarder(logRotator(numToKeepStr: '10'))
            timestamps()
            timeout(time: 1, unit: 'HOURS')
            disableConcurrentBuilds()
        }
    
        stages {
            stage('Checkout') {
                steps {
                    checkout scm
                    script {
                        env.GIT_COMMIT_MSG = sh(
                            returnStdout: true,
                            script: 'git log -1 --pretty=%B'
                        ).trim()
                    }
                }
            }
    
            stage('Build') {
                steps {
                    sh '''
                        docker build 
                            --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') 
                            --build-arg VCS_REF=$GIT_COMMIT_SHORT 
                            --cache-from $IMAGE_NAME:latest 
                            -t $IMAGE_NAME:$GIT_COMMIT_SHORT 
                            -t $IMAGE_NAME:latest 
                            .
                    '''
                }
            }
    
            stage('Test') {
                parallel {
                    stage('Unit Tests') {
                        steps {
                            sh '''
                                docker run --rm 
                                    $IMAGE_NAME:$GIT_COMMIT_SHORT 
                                    npm test
                            '''
                        }
                    }
    
                    stage('Security Scan') {
                        steps {
                            sh '''
                                docker run --rm 
                                    -v /var/run/docker.sock:/var/run/docker.sock 
                                    aquasec/trivy image 
                                    --exit-code 1 
                                    --severity HIGH,CRITICAL 
                                    $IMAGE_NAME:$GIT_COMMIT_SHORT
                            '''
                        }
                    }
                }
            }
    
            stage('Push to Registry') {
                when {
                    branch 'main'
                }
                steps {
                    sh '''
                        echo $DOCKER_CREDENTIALS_PSW | 
                            docker login -u $DOCKER_CREDENTIALS_USR --password-stdin $DOCKER_REGISTRY
    
                        docker push $IMAGE_NAME:$GIT_COMMIT_SHORT
                        docker push $IMAGE_NAME:latest
                    '''
                }
            }
    
            stage('Deploy to Staging') {
                when {
                    branch 'main'
                }
                steps {
                    sshagent(credentials: ['deploy-ssh-key']) {
                        sh '''
                            ssh -o StrictHostKeyChecking=accept-new deploy@staging.monapp.com \\
                                "cd /opt/myapp && IMAGE_TAG=$GIT_COMMIT_SHORT docker compose pull && IMAGE_TAG=$GIT_COMMIT_SHORT docker compose up -d"
                        '''
                    }
                }
            }
    
            stage('Approval') {
                when {
                    branch 'main'
                }
                steps {
                    timeout(time: 24, unit: 'HOURS') {
                        input message: 'Deploy to production?',
                              ok: 'Deploy',
                              submitter: 'admin,devops-team'
                    }
                }
            }
    
            stage('Deploy to Production') {
                when {
                    branch 'main'
                }
                steps {
                    sshagent(credentials: ['deploy-ssh-key']) {
                        sh '''
                            ssh -o StrictHostKeyChecking=accept-new deploy@monapp.com \\
                                "cd /opt/myapp && IMAGE_TAG=$GIT_COMMIT_SHORT docker compose pull && IMAGE_TAG=$GIT_COMMIT_SHORT docker compose up -d"
                        '''
                    }
                }
            }
        }
    
        post {
            success {
                slackSend(
                    color: 'good',
                    message: "✅ Build SUCCESS: ${env.JOB_NAME} #${env.BUILD_NUMBER}nCommit: ${env.GIT_COMMIT_MSG}"
                )
            }
            failure {
                slackSend(
                    color: 'danger',
                    message: "❌ Build FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}nCommit: ${env.GIT_COMMIT_MSG}"
                )
            }
            always {
                cleanWs()
            }
        }
    }
    

    Meilleures Pratiques CI/CD 2025

    1. Fail Fast : Tester Tôt

    Exécutez les tests unitaires en premier pour détecter rapidement les erreurs. Les tests rapides (linting, unit tests) doivent s’exécuter avant les tests lents (intégration, E2E).

    # Ordre optimal des stages
    stages:
      - lint        # < 1 minute
      - unit-test   # 2-5 minutes
      - build       # 3-10 minutes
      - integration # 5-15 minutes
      - e2e         # 10-30 minutes
      - deploy      # Variable
    

    2. Cache des Dépendances

    Mettez en cache les dépendances pour accélérer les builds. Les pipelines peuvent passer de 10 minutes à 2 minutes avec un bon cache.

    GitHub Actions :

    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'  # Cache automatique
    

    GitLab CI :

    cache:
      key: ${CI_COMMIT_REF_SLUG}
      paths:
        - node_modules/
        - .npm/
    

    Jenkins :

    stage('Install') {
        steps {
            cache(maxCacheSize: 500, caches: [
                arbitraryFileCache(
                    path: 'node_modules',
                    cacheValidityDecidingFile: 'package-lock.json'
                )
            ]) {
                sh 'npm ci'
            }
        }
    }
    

    3. Testcontainers pour Reproductibilité

    Utilisez Testcontainers pour des environnements de test reproductibles avec bases de données, caches, etc.

    // Exemple avec Testcontainers
    const { GenericContainer } = require('testcontainers');
    
    describe('Integration Tests', () => {
      let postgresContainer;
      let redisContainer;
    
      beforeAll(async () => {
        postgresContainer = await new GenericContainer('postgres:16-alpine')
          .withEnvironment({ POSTGRES_PASSWORD: 'test' })
          .withExposedPorts(5432)
          .start();
    
        redisContainer = await new GenericContainer('redis:7-alpine')
          .withExposedPorts(6379)
          .start();
    
        process.env.DATABASE_URL = postgresql://postgres:test@localhost:${postgresContainer.getMappedPort(5432)}/test;
        process.env.REDIS_URL = redis://localhost:${redisContainer.getMappedPort(6379)};
      });
    
      afterAll(async () => {
        await postgresContainer.stop();
        await redisContainer.stop();
      });
    
      // Vos tests ici
    });
    

    4. Sécuriser les Credentials

    Ne JAMAIS stocker de credentials en clair dans les fichiers YAML. Utilisez les gestionnaires de secrets de la plateforme.

    GitHub Actions :

    - name: Deploy
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      run: aws s3 sync ./dist s3://my-bucket
    

    GitLab CI (avec Vault) :

    variables:
      VAULT_ADDR: https://vault.monentreprise.com
      VAULT_AUTH_ROLE: gitlab-ci
    
    deploy:
      id_tokens:
        VAULT_ID_TOKEN:
          aud: https://vault.monentreprise.com
      secrets:
        DATABASE_PASSWORD:
          vault: production/database/password@secret
      script:
        - echo "Password: $DATABASE_PASSWORD"
    

    5. Isoler Build et Déploiement

    Séparez les stages de build et de déploiement pour une meilleure traçabilité.

    # ❌ Mauvais : Tout ensemble
    deploy:
      script:
        - npm run build
        - docker build -t myapp .
        - ssh deploy@serveur "cd /opt/myapp && docker compose up -d"
    
    # ✅ Bon : Séparé et tracé
    build:
      script:
        - npm run build
        - docker build -t myapp:$CI_COMMIT_SHA .
        - docker push myapp:$CI_COMMIT_SHA
    
    deploy:
      needs: [build]
      script:
        - ssh deploy@serveur "cd /opt/myapp && IMAGE_TAG=$CI_COMMIT_SHA docker compose up -d"
    

    6. Tags d'Image Basés sur Commit SHA

    Utilisez le SHA du commit pour une traçabilité complète.

    # ✅ Excellent
    docker build -t monapp:$(git rev-parse --short HEAD) .
    docker build -t monapp:${CI_COMMIT_SHA} .
    
    # ⚠️ Acceptable (avec versioning)
    docker build -t monapp:v1.2.3 .
    
    # ❌ Mauvais : Impossible de tracer
    docker build -t monapp:latest .
    

    7. Ne Pas Échouer Silencieusement

    Erreur critique : Ne pas faire échouer le build sur des problèmes de tests ou de sécurité. "Rapide mais cassé" est pire que lent.

    # ✅ Bon : Pipeline échoue si problème
    security-scan:
      script:
        - trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest
    
    # ❌ Mauvais : Ignore les erreurs
    security-scan:
      script:
        - trivy image myapp:latest || true  # Continue même si vulnérabilités!
    

    8. Pouvoir revenir en arrière

    Un déploiement qui se passe mal ne doit pas être une catastrophe : il faut pouvoir revenir à la version précédente en une commande.

    Rollback avec Docker Compose :

    # docker-compose.yml : l'image est choisie par une variable
    services:
      myapp:
        image: registry.exemple.net/myapp:${IMAGE_TAG:-latest}
        restart: unless-stopped
    
    # Déployer une version
    IMAGE_TAG=a1b2c3d docker compose up -d
    
    # Revenir à la précédente (le tag du commit d'avant)
    IMAGE_TAG=9f8e7d6 docker compose up -d
    

    Conservez les images des dernières versions dans le registre et notez le tag déployé : c'est tout ce qu'il faut pour un retour arrière rapide.

    9. Pipelines Versionnés dans Git

    Vos pipelines CI/CD font partie du code. Versionnez-les, reviewez-les, testez-les.

    # Structure recommandée
    .github/
      workflows/
        ci.yml              # CI principal
        deploy-staging.yml  # Déploiement staging
        deploy-prod.yml     # Déploiement production
        security.yml        # Scans de sécurité
        release.yml         # Création de releases
    
    .gitlab-ci/
      templates/
        build.yml
        test.yml
        deploy.yml
    .gitlab-ci.yml  # Fichier principal qui inclut les templates
    

    10. Monitoring et Alerting des Pipelines

    Surveillez la santé de vos pipelines comme vous surveillez vos applications.

    Métriques clés :

  • Lead time : Temps commit → production
  • Deployment frequency : Nombre de déploiements/jour
  • Change failure rate : % de déploiements causant des incidents
  • MTTR : Mean Time To Recovery
  • Exemple avec Prometheus :

    # Exporter des métriques depuis GitHub Actions
    - name: Export metrics
      run: |
        echo "pipeline_duration_seconds{job="$GITHUB_JOB",status="${{ job.status }}"} $SECONDS" | 
          curl --data-binary @- http://pushgateway:9091/metrics/job/github-actions
    

    Tendances 2025 et Au-Delà

    AI-Driven Testing

    Les tests sont de plus en plus optimisés par l'IA, qui sélectionne les tests pertinents basés sur les changements de code.

    # Exemple avec AI Test Selection
    test:
      script:
        - ai-test-selector --changed-files="$(git diff --name-only HEAD~1)" 
                           --run-tests
        # Exécute uniquement les tests affectés par les changements
    

    GitOps Généralisé

    Les équipes adoptent GitOps : la configuration de déploiement vit dans Git, et chaque changement passe par un commit. Un simple dépôt contenant vos docker-compose.yml, déployé par un pipeline, suffit pour en profiter.

    Platform Engineering

    Les équipes créent des "golden paths" : templates de pipelines réutilisables.

    # Template réutilisable GitLab
    # templates/nodejs-app.yml
    .nodejs-app:
      image: node:20-alpine
      cache:
        key: ${CI_COMMIT_REF_SLUG}
        paths:
          - node_modules/
      before_script:
        - npm ci
    

    Checklist de Pipeline Production-Ready

    Avant de déployer en production, vérifiez :

    Tests :

  • [ ] Tests unitaires (couverture > 80%)
  • [ ] Tests d'intégration
  • [ ] Tests E2E sur environnement staging
  • [ ] Tests de performance/charge
  • Sécurité :

  • [ ] SAST (analyse statique du code)
  • [ ] Dependency scanning (vulnérabilités dépendances)
  • [ ] Container scanning (vulnérabilités images Docker)
  • [ ] DAST (tests dynamiques) sur staging
  • [ ] Secrets managés correctement (Vault/Secrets Manager)
  • Déploiement :

  • [ ] Déploiements progressifs (blue/green ou canary)
  • [ ] Rollback automatique si échec health check
  • [ ] Zero-downtime deployment
  • [ ] Database migrations gérées
  • Observabilité :

  • [ ] Logs centralisés (ELK, Loki)
  • [ ] Métriques exposées (Prometheus)
  • [ ] Tracing distribué (Jaeger, Tempo)
  • [ ] Alerting configuré (Alertmanager, PagerDuty)
  • Qualité :

  • [ ] Linting automatique
  • [ ] Formattage automatique (Prettier, Black)
  • [ ] Analyse de code (SonarQube)
  • [ ] Review required avant merge
  • Conclusion

    Le paysage CI/CD en 2025 offre des outils puissants et accessibles pour automatiser vos workflows de développement. Le choix entre GitHub Actions, GitLab CI et Jenkins dépend de votre contexte :

  • GitHub Actions : Parfait pour projets GitHub, setup rapide, excellent marketplace
  • GitLab CI : Meilleur pour DevSecOps, plateforme complète
  • Jenkins : Idéal pour legacy, maximum de flexibilité, écosystème mature
  • Principes universels :

  • Fail fast : Tests rapides en premier
  • Security by default : SAST/DAST intégrés
  • GitOps : Tout versionné, tout déclaratif
  • Observability : Monitorer vos pipelines
  • Retour arrière facile : Images taguées par commit
  • L'avenir est aux pipelines intelligents (AI-driven), aux déploiements déclaratifs (GitOps) et aux plateformes d'ingénierie qui démocratisent les meilleures pratiques.

    Sources et Références

  • CI/CD Pipelines Explained - Medium
  • 12 Steps to Implement CI/CD - DevOps Training Institute
  • Ultimate Guide to CI/CD Pipelines 2025
  • State of CI/CD 2025 - JetBrains Survey
  • GitHub Actions vs Jenkins 2025 - Northflank
  • Top GitLab CI/CD Pipeline Examples

  • Article mis à jour en décembre 2025 avec les dernières tendances CI/CD et outils de l'écosystème DevOps.

    À propos de l'auteur

    Pascal

    Pascal — SRE & Observability Engineer. J'applique les pratiques SRE (SLI/SLO, alerting, observabilité) à mon homelab Proxmox, avec les mêmes exigences qu'en production.

    Une remarque, un retour ?

    Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisis celui qui te convient.

    Laisser un commentaire