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.