CI/CD

Jenkins

Pipelines Jenkins, Jenkinsfile, agents et bonnes pratiques CI/CD.

jenkinscicdpipelineautomatisationdevops

Architecture

Jenkins fonctionne sur un modèle Controller / Agent :

ComposantRôle
ControllerOrchestration, interface web, configuration des jobs
AgentExécution des builds sur des machines dédiées
ExecutorThread d'exécution sur un agent (plusieurs par agent)
PluginExtension des fonctionnalités (Git, Docker, Slack, etc.)

Jenkinsfile — Pipeline déclarative

pipeline {
    agent any
 
    environment {
        NODE_ENV = 'production'
        REGISTRY = 'registry.example.com'
    }
 
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
 
        stage('Build') {
            steps {
                sh 'npm ci'
                sh 'npm run build'
            }
        }
 
        stage('Test') {
            steps {
                sh 'npm test'
            }
        }
 
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh './deploy.sh'
            }
        }
    }
 
    post {
        always {
            cleanWs()
        }
        success {
            echo 'Déploiement réussi !'
        }
        failure {
            echo 'Échec du pipeline'
        }
    }
}

Agents

Agent global

pipeline {
    agent any
    // Exécute sur n'importe quel agent disponible
}

Agent Docker

pipeline {
    agent {
        docker {
            image 'node:20-alpine'
            args '-v /tmp:/tmp'
        }
    }
}

Agent Kubernetes

pipeline {
    agent {
        kubernetes {
            yaml '''
                apiVersion: v1
                kind: Pod
                spec:
                  containers:
                  - name: maven
                    image: maven:3.9-eclipse-temurin-21
                    command: ['sleep']
                    args: ['infinity']
            '''
        }
    }
}

Agent par label

pipeline {
    agent { label 'linux && docker' }
}

Variables & Paramètres

Variables d'environnement

environment {
    APP_VERSION = sh(script: 'cat VERSION', returnStdout: true).trim()
    DB_CREDS = credentials('db-credentials')
    // DB_CREDS_USR et DB_CREDS_PSW sont créés automatiquement
}

Paramètres de build

parameters {
    string(name: 'BRANCH', defaultValue: 'main', description: 'Branche à déployer')
    choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: 'Environnement cible')
    booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Ignorer les tests')
}

Utilisation : ${params.BRANCH}, ${params.ENV}

Credentials

withCredentials([
    usernamePassword(
        credentialsId: 'docker-hub',
        usernameVariable: 'DOCKER_USER',
        passwordVariable: 'DOCKER_PASS'
    )
]) {
    sh 'docker login -u $DOCKER_USER -p $DOCKER_PASS'
}

Triggers

triggers {
    // Vérifier le SCM toutes les 5 minutes
    pollSCM('H/5 * * * *')
 
    // Build planifié (cron)
    cron('H 2 * * 1-5')
 
    // Déclenché par un autre job
    upstream(upstreamProjects: 'build-lib', threshold: hudson.model.Result.SUCCESS)
}

Pour les webhooks GitHub/GitLab, configurer le plugin correspondant et activer le trigger dans la configuration du job.

Étapes parallèles

stage('Tests') {
    parallel {
        stage('Unit Tests') {
            steps {
                sh 'npm run test:unit'
            }
        }
        stage('Integration Tests') {
            steps {
                sh 'npm run test:integration'
            }
        }
        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }
    }
}

Post actions

post {
    always {
        // Toujours exécuté (nettoyage, rapports)
        junit '**/test-results/*.xml'
        archiveArtifacts artifacts: 'dist/**', allowEmptyArchive: true
    }
    success {
        slackSend channel: '#deploys', message: "✅ ${env.JOB_NAME} #${env.BUILD_NUMBER}"
    }
    failure {
        slackSend channel: '#alerts', message: "❌ ${env.JOB_NAME} #${env.BUILD_NUMBER}"
    }
    unstable {
        echo 'Tests instables détectés'
    }
    changed {
        echo 'Le statut du build a changé'
    }
}

Pipeline avancée

Conditions (when)

stage('Deploy Prod') {
    when {
        allOf {
            branch 'main'
            not { changeRequest() }
            environment name: 'DEPLOY', value: 'true'
        }
    }
    steps {
        sh './deploy-prod.sh'
    }
}

Input (approbation manuelle)

stage('Approval') {
    steps {
        input message: 'Déployer en production ?', ok: 'Déployer'
    }
}

Shared Libraries

// Jenkinsfile
@Library('my-shared-lib') _
 
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                buildApp(language: 'node', version: '20')
            }
        }
    }
}

Structure de la librairie partagée :

vars/
  buildApp.groovy      # Fonctions globales
  deployTo.groovy
src/
  org/example/Utils.groovy  # Classes
resources/
  templates/                # Fichiers de configuration

Bonnes pratiques

PratiqueDétail
Pipeline as CodeJenkinsfile versionné dans le dépôt Git
DéclaratifPréférer la syntaxe déclarative à la scriptée
Agents éphémèresUtiliser Docker/K8s pour des environnements propres
CredentialsJamais de secrets en dur, toujours credentials()
ParallélismeExécuter les tests en parallèle pour réduire la durée
Shared LibrariesFactoriser la logique commune entre pipelines
NettoyagecleanWs() en post-action pour libérer l'espace