JenkinsCI/CDDevOps

Jenkins : écrire des pipelines robustes avec Jenkinsfile

14 avril 2026 · Sphinx-Digital

Un pipeline Jenkins mal écrit, c’est un pipeline qu’on évite de toucher. Un Jenkinsfile bien structuré, c’est un actif d’équipe — versionné, relu, amélioré comme du code. La différence tient à quelques pratiques.

Pipeline déclaratif : la structure de référence

Le format déclaratif est le standard actuel. Il impose une structure claire et lisible :

pipeline {
  agent { docker { image 'python:3.12-slim' } }

  environment {
    REGISTRY = 'registry.example.com'
    IMAGE    = "${REGISTRY}/myapp:${BUILD_NUMBER}"
  }

  stages {
    stage('Tests') {
      steps {
        sh 'pip install -r requirements.txt'
        sh 'pytest tests/ --junitxml=results.xml'
      }
      post {
        always { junit 'results.xml' }
      }
    }

    stage('Build') {
      steps {
        sh "docker build -t ${IMAGE} ."
      }
    }

    stage('Push') {
      when { branch 'main' }
      steps {
        withCredentials([usernamePassword(credentialsId: 'registry-creds',
            usernameVariable: 'USER', passwordVariable: 'PASS')]) {
          sh "echo $PASS | docker login ${REGISTRY} -u $USER --password-stdin"
          sh "docker push ${IMAGE}"
        }
      }
    }
  }
}

Quelques points clés : l’agent Docker isole l’environnement d’exécution, when { branch 'main' } limite le push aux merges sur main, withCredentials ne fait jamais apparaître les secrets dans les logs.

Parallélisme : accélérer les suites de tests

Quand les tests prennent trop de temps, le parallélisme est la première optimisation :

stage('Tests parallèles') {
  parallel {
    stage('Unit') {
      steps { sh 'pytest tests/unit/' }
    }
    stage('Integration') {
      agent { label 'docker-agent' }
      steps { sh 'pytest tests/integration/' }
    }
    stage('Lint') {
      steps { sh 'ruff check .' }
    }
  }
}

Les trois stages s’exécutent simultanément sur des agents potentiellement différents. Sur une suite de 10 minutes, vous pouvez descendre à 4 minutes.

Gestion des erreurs et notifications

post {
  failure {
    slackSend(
      channel: '#ops-alerts',
      color: 'danger',
      message: "❌ Build #${BUILD_NUMBER} échoué — ${env.JOB_NAME}\n${env.BUILD_URL}"
    )
  }
  success {
    slackSend(channel: '#deployments', color: 'good',
      message: "✅ ${IMAGE} déployé en prod")
  }
  always {
    cleanWs()   // nettoyer le workspace après chaque build
  }
}

Shared Libraries : factoriser entre projets

Quand plusieurs projets partagent la même logique de pipeline, les Shared Libraries évitent la duplication :

// vars/buildAndPush.groovy (dans le dépôt de shared library)
def call(String imageName) {
  sh "docker build -t ${imageName}:${BUILD_NUMBER} ."
  sh "docker push ${imageName}:${BUILD_NUMBER}"
}
// Dans n'importe quel Jenkinsfile de l'organisation
@Library('sphinx-shared-lib') _

pipeline {
  stages {
    stage('Build') {
      steps { buildAndPush('registry.example.com/myapp') }
    }
  }
}

Un seul endroit pour maintenir la logique de build. Tous les projets qui utilisent la library en bénéficient instantanément.

Configuration as Code : ne jamais cliquer dans l’UI

Jenkins Configuration as Code (JCasC) permet de définir toute la configuration Jenkins dans un fichier YAML versionné :

jenkins:
  systemMessage: "Sphinx-Digital CI"
  numExecutors: 0
  clouds:
    - kubernetes:
        name: k8s
        serverUrl: https://kubernetes.default
        namespace: jenkins

Notre formation Jenkins couvre ces pratiques sur deux jours, du premier pipeline à l’intégration Kubernetes.