Pipelines Jenkins
Introduction aux Pipelines
Un pipeline Jenkins est une suite d'étapes automatisées définies en code Groovy.
Pipeline Déclaratif vs Scripté
Déclaratif (Recommandé)
Structure prédéfinie, plus simple à apprendre.
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
}
Scripté
Plus flexible, syntaxe Groovy pure.
node {
stage('Build') {
sh 'mvn clean package'
}
}
Comparaison
| Aspect | Déclaratif | Scripté |
|---|---|---|
| Syntaxe | Structurée | Libre |
| Flexibilité | Moyenne | Haute |
| Validation | À l'écriture | À l'exécution |
| Apprentissage | Facile | Moyen |
| Recommandé | ✅ Oui | Pour cas complexes |
Structure d'un Pipeline Déclaratif
pipeline {
// Où exécuter le pipeline
agent any
// Variables d'environnement
environment {
APP_NAME = 'my-app'
VERSION = '1.0.0'
}
// Options globales
options {
timeout(time: 30, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '10'))
}
// Paramètres d'entrée
parameters {
string(name: 'BRANCH', defaultValue: 'main')
choice(name: 'ENV', choices: ['dev', 'prod'])
}
// Déclencheurs
triggers {
pollSCM('H/5 * * * *')
}
// Étapes du pipeline
stages {
stage('Build') {
steps {
sh 'echo "Building ${APP_NAME}"'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Deploy') {
steps {
sh 'kubectl apply -f k8s/'
}
}
}
// Actions post-pipeline
post {
always {
cleanWs()
}
success {
slackSend message: "Build réussi!"
}
failure {
mail to: '[email protected]',
subject: "Build échoué: ${JOB_NAME}",
body: "Vérifier: ${BUILD_URL}"
}
}
}
Agent
L'agent définit où le pipeline s'exécute.
Types d'agents
// N'importe quel agent disponible
agent any
// Pas d'agent (pour stages individuels)
agent none
// Agent avec label spécifique
agent {
label 'linux'
}
// Agent Docker
agent {
docker {
image 'node:18'
args '-v /tmp:/tmp'
}
}
// Agent Kubernetes
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8-openjdk-17
command: ['sleep', 'infinity']
'''
}
}
// Dockerfile dans le repo
agent {
dockerfile {
filename 'Dockerfile.build'
dir 'docker'
args '-v /tmp:/tmp'
}
}
Agent par stage
pipeline {
agent none
stages {
stage('Build') {
agent {
docker { image 'maven:3.8' }
}
steps {
sh 'mvn clean package'
}
}
stage('Test') {
agent {
docker { image 'node:18' }
}
steps {
sh 'npm test'
}
}
stage('Deploy') {
agent {
label 'kubernetes'
}
steps {
sh 'kubectl apply -f k8s/'
}
}
}
}
Stages et Steps
Stage
Un stage est une phase logique du pipeline.
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify -Pintegration'
}
}
stage('Deploy') {
steps {
sh './deploy.sh'
}
}
}
Steps courants
steps {
// Exécuter un script shell
sh 'echo "Hello"'
sh '''
echo "Multi-line"
echo "Script"
'''
// Windows batch
bat 'echo Hello'
// PowerShell
powershell 'Write-Host "Hello"'
// Checkout Git
checkout scm
git branch: 'main', url: 'https://github.com/user/repo.git'
// Afficher un message
echo 'Building...'
// Archiver des artifacts
archiveArtifacts artifacts: 'target/*.jar'
// Publier les résultats de tests
junit 'target/surefire-reports/*.xml'
// Envoyer un email
mail to: '[email protected]',
subject: 'Build',
body: 'Done'
// Slack
slackSend channel: '#builds',
message: "Build ${BUILD_NUMBER} terminé"
// Attendre une approbation
input message: 'Déployer en production?'
// Définir une variable
script {
env.MY_VAR = 'value'
}
}
Parallélisation
Stages parallèles
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Tests') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify'
}
}
stage('E2E Tests') {
agent {
docker { image 'cypress/included' }
}
steps {
sh 'cypress run'
}
}
}
}
stage('Deploy') {
steps {
sh 'kubectl apply -f k8s/'
}
}
}
}
Matrix
pipeline {
agent none
stages {
stage('Test Matrix') {
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'windows', 'mac'
}
axis {
name 'NODE_VERSION'
values '16', '18', '20'
}
}
excludes {
exclude {
axis {
name 'PLATFORM'
values 'mac'
}
axis {
name 'NODE_VERSION'
values '16'
}
}
}
stages {
stage('Test') {
agent {
label "${PLATFORM}"
}
steps {
sh "nvm use ${NODE_VERSION} && npm test"
}
}
}
}
}
}
}
Conditions
When
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
stage('Deploy to Dev') {
when {
branch 'develop'
}
steps {
sh 'kubectl apply -f k8s/dev/'
}
}
stage('Deploy to Prod') {
when {
allOf {
branch 'main'
environment name: 'DEPLOY', value: 'true'
}
}
steps {
sh 'kubectl apply -f k8s/prod/'
}
}
stage('Nightly Build') {
when {
triggeredBy 'TimerTrigger'
}
steps {
sh 'mvn clean install'
}
}
stage('PR Build') {
when {
changeRequest()
}
steps {
sh 'mvn verify'
}
}
}
Conditions disponibles
when {
// Branche spécifique
branch 'main'
branch pattern: 'release-*', comparator: 'GLOB'
// Tag
tag 'v*'
// Environnement
environment name: 'ENV', value: 'prod'
// Expression Groovy
expression { return params.DEPLOY == true }
// Fichier modifié
changeset '**/*.java'
// Pull Request
changeRequest()
changeRequest target: 'main'
// Combinaisons
allOf {
branch 'main'
environment name: 'DEPLOY', value: 'true'
}
anyOf {
branch 'main'
branch 'develop'
}
not {
branch 'feature/*'
}
}
Gestion des erreurs
Try-Catch
pipeline {
agent any
stages {
stage('Deploy') {
steps {
script {
try {
sh 'kubectl apply -f k8s/'
} catch (Exception e) {
echo "Deployment failed: ${e.message}"
sh 'kubectl rollback'
throw e
}
}
}
}
}
}
catchError
stage('Tests') {
steps {
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh 'npm test'
}
}
}
Retry et Timeout
stage('Deploy') {
steps {
retry(3) {
timeout(time: 5, unit: 'MINUTES') {
sh 'kubectl apply -f k8s/'
}
}
}
}
Post Actions
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
}
post {
// Toujours exécuté
always {
junit 'target/surefire-reports/*.xml'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
cleanWs()
}
// Si succès
success {
slackSend color: 'good', message: "Build #${BUILD_NUMBER} réussi"
}
// Si échec
failure {
slackSend color: 'danger', message: "Build #${BUILD_NUMBER} échoué"
mail to: '[email protected]',
subject: "FAILED: ${JOB_NAME} #${BUILD_NUMBER}",
body: "Check: ${BUILD_URL}"
}
// Si instable (tests échoués)
unstable {
slackSend color: 'warning', message: "Build instable"
}
// Si changement de statut
changed {
echo 'Le statut du build a changé'
}
// Si revenu à la normale
fixed {
slackSend color: 'good', message: "Build réparé!"
}
// Si annulé
aborted {
echo 'Build annulé'
}
}
}
Résumé
| Concept | Description |
|---|---|
| Pipeline | Workflow CI/CD en code |
| Déclaratif | Syntaxe structurée (recommandé) |
| Scripté | Groovy pur (flexible) |
| Stage | Phase logique |
| Step | Action unitaire |
| Agent | Où s'exécute le build |
| When | Conditions d'exécution |
| Post | Actions post-build |