⚙️ Jenkins – CI/CD, Pipelines & Déploiement
Guide complet IDEO‑Lab sur le serveur d'intégration continue (Pipeline, Groovy, Jenkinsfile).
Vue d'ensemble
CI/CD, Serveur d'automatisation, Jobs.
CI/CD AutomatisationArchitecture
Controller (Master) / Agent (Slave).
Controller AgentPrérequis : Java (JDK)
Installation OpenJDK (11 ou 17 Requis).
Java JDK 11/17Installation Linux
apt (Debian/Ubuntu) & dnf (RHEL/Rocky).
Installation Docker
docker run (persistance), docker-compose.
Setup Wizard
Déverrouillage, initialAdminPassword, plugins.
Gérer Jenkins & Plugins
Gérer les plugins (install, update).
Manage Jenkins PluginsJob 1: Freestyle Project
Le job "classique" (via l'UI), SCM, Build steps.
Freestyle UIPipeline as Code
Jenkinsfile, "Pipeline as Code", SCM.
Declarative vs Scripted
Comparaison des deux syntaxes Pipeline.
Declarative ScriptedDeclarative: Syntaxe
pipeline, agent, stages, steps, post, environment.
Declarative: Steps (étapes)
sh, bat, dir, git, junit, archiveArtifacts.
Scripted Pipeline (Groovy)
node {}, stage {}, syntaxe Groovy, try/catch.
Shared Libraries
Factoriser le code (vars/), @Library.
Multibranch Pipeline
Scan auto des branches (Jenkinsfile).
Artifacts & Credentials
archiveArtifacts, stash, withCredentials.
Triggers (Déclencheurs)
cron, pollSCM, Webhooks (GitHub).
Blue Ocean (UI)
Interface moderne pour visualiser les Pipelines.
Blue Ocean UISécurité (Matrix)
Gestion des utilisateurs, Matrix Security.
Security MatrixCheat-sheet Jenkinsfile
Syntaxe Declarative (pipeline, stages, steps...).
Qu'est-ce que Jenkins ?
Jenkins est un serveur d'automatisation open-source (écrit en Java). C'est l'outil de **CI/CD** (Intégration Continue / Déploiement Continu) le plus utilisé au monde.
Son rôle est d'automatiser les phases non-humaines du développement logiciel (build, test, déploiement).
CI/CD (Intégration Continue / Déploiement Continu)
CI (Continuous Integration) :
- Un développeur "push" son code vers Git.
- Jenkins détecte le push (via Webhook).
- Jenkins "build" le projet (ex:
npm install,mvn package). - Jenkins lance les tests unitaires (
npm test). - Jenkins rapporte le résultat (OK/Échec) au développeur.
CD (Continuous Deployment) :
- Si la CI est OK, Jenkins "package" l'application (ex: image Docker).
- Jenkins déploie l'application sur un serveur (Staging, Prod).
Jenkins vs (GitLab CI, GitHub Actions)
| Critère | Jenkins | GitLab CI / GitHub Actions |
|---|---|---|
| Hébergement | Auto-hébergé (On-premise / VPS). | SaaS (Cloud) ou Auto-hébergé (Runners). |
| Flexibilité | Extrême. Des milliers de plugins. | Plus simple, mais lié à l'écosystème Git. |
| Configuration | Jenkinsfile (Groovy) ou UI. | .gitlab-ci.yml / .github/workflows/ (YAML). |
| Courbe d'apprentissage | Élevée (Java, Plugins, Agents). | Moyenne (YAML). |
Controller (ex-Master)
Le Controller (Contrôleur) est le serveur central (le "cerveau").
Il ne fait pas de travail de build.
- Stocke la configuration (jobs, plugins).
- Gère l'interface web (Port 8080).
- Planifie et distribue les "builds" aux Agents.
Agent (ex-Slave)
Un Agent (Agent) est un "worker" (l'esclave) qui exécute les tâches.
- Peut être une VM, un conteneur Docker, un pod K8s.
- Possède les "outils" (ex: Java, Node.js, Docker).
- Reçoit les ordres du Controller ("Build ce projet") et exécute les étapes.
Schéma de flux
[Image d'une architecture Jenkins Controller/Agent] (Dev -> 'git push') | ▼ (Webhook) +-----------------------+ | Controller (Serveur) | | (Port 8080) | | (Gère l'UI, Planifie) | +-----------------------+ | | (Lance le build via SSH ou JNLP) | +----------+-----------------+ | | | ▼ ▼ ▼ +--------+ +--------+ +--------+ | Agent 1| | Agent 2| | Agent 3| | (Linux)| | (Win) | | (Docker)| | (Java 11)| (NodeJS) | | (Python)| +--------+ +--------+ +--------+ (Exécute le build, 'npm install'...)
Jenkins est Java
Jenkins est une application .war (Web Archive) Java. Il nécessite un Java Development Kit (JDK) (ou JRE) pour s'exécuter (sur le Controller et les Agents).
Version Requise
- Jenkins LTS (actuel) : Java 11 ou Java 17. (Java 8 est obsolète).
Installation (OpenJDK 17 - Ubuntu/Debian)
sudo apt update sudo apt install -y openjdk-17-jdk # Vérifier java -version # openjdk version "17.0.x" ...
Installation (OpenJDK 17 - RHEL/Rocky)
sudo dnf install -y java-17-openjdk-devel # Vérifier java -version
Ubuntu / Debian (Dépôt officiel Jenkins)
# (Assurez-vous que JDK 17 est installé) # 1. Ajouter la clé GPG curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \ /usr/share/keyrings/jenkins-keyring.asc > /dev/null # 2. Ajouter le dépôt echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \ https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins.list > /dev/null # 3. Installer sudo apt-get update sudo apt-get install -y jenkins
RHEL / Rocky / AlmaLinux (Dépôt officiel)
# 1. Ajouter le dépôt
sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat-stable/jenkins.repo
# 2. Importer la clé GPG
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key
# 3. Installer
sudo dnf install -y jenkinsPost-Installation (systemd)
# Démarrer et activer sudo systemctl enable --now jenkins # Vérifier le statut sudo systemctl status jenkins # (Données Jenkins) # /var/lib/jenkins (JENKINS_HOME) # (Configuration) # /etc/default/jenkins (Debian) # /etc/sysconfig/jenkins (RHEL)
Une fois démarré, Jenkins est accessible sur http://[IP_SERVEUR]:8080.
(Ouvrir le port 8080 dans le firewall !)
docker run (Simple)
L'image officielle (jenkins/jenkins:lts) est recommandée. La persistance de /var/jenkins_home est cruciale.
docker run -d \
--name jenkins \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts-jdk17
# -p 8080: (UI Web)
# -p 50000: (Agents JNLP)
# -v jenkins_home:... (Volume pour les données)docker-compose.yml (Plus robuste)
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk17
container_name: jenkins
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home_data:/var/jenkins_home
restart: unless-stopped
volumes:
jenkins_home_data:1. Déverrouillage
Lors du premier accès (http://localhost:8080), Jenkins demande un mot de passe initial (pour prouver que vous êtes l'admin).
Ce mot de passe se trouve sur le serveur :
# (Si install Linux) sudo cat /var/lib/jenkins/secrets/initialAdminPassword # (Si install Docker) docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
2. Plugins & Admin
Customize Jenkins :
-> "Install suggested plugins" (Recommandé pour les débutants).
Create First Admin User :
Créez votre propre compte (ex: ideo_admin) pour ne plus utiliser le mot de passe généré.
"Manage Jenkins" (Administrer Jenkins)
C'est le panneau de configuration central de Jenkins. C'est ici que vous gérez :
- System : Configuration globale (URL, variables d'env...).
- Tools : (Important) Définir les outils (JDK, Git, Node.js) pour les Agents.
- Nodes and Clouds : Ajouter/Gérer les Agents.
- Credentials : (Important) Stocker les secrets (mots de passe, clés SSH).
- Plugins : Gérer les plugins.
- Security : Gérer les utilisateurs et les permissions.
Gestion des Plugins
La puissance de Jenkins vient de ses plugins. (Manage Jenkins -> Plugins).
Plugins "indispensables" à installer (s'ils ne le sont pas) :
| Plugin | Usage |
|---|---|
| Blue Ocean | (Voir 5.1) Interface UI moderne pour les Pipelines. |
| Pipeline | (Core) Le moteur Jenkinsfile. |
| Git | Intégration Git. |
| Docker Pipeline | Permet d'utiliser docker.build(), docker.run() dans un Jenkinsfile. |
| SSH Agent | Fournit des clés SSH aux builds (pour git pull ou ssh deploy). |
L'ancien mode (via l'UI)
Un "Freestyle Project" est le job historique de Jenkins. Toute la configuration se fait via l'interface graphique (clics, formulaires).
Avantage : Très simple pour les débutants et les tâches basiques.
Inconvénient : La configuration n'est pas versionnée (pas dans Git). Difficile à reproduire.
Création
- Dashboard -> New Item.
- Entrer un nom (ex: "Mon_Job_Freestyle").
- Choisir Freestyle project.
Configuration (SCM)
Dans la page de configuration du job :
Source Code Management (SCM) :
- Cocher Git.
- Repository URL :
https://github.com/mon-user/mon-projet.git - Credentials : (Ajouter un "Username with password" ou "SSH Username")
- Branch Specifier :
*/main
Configuration (Build & Post)
Build Steps :
Add build step-> Execute shell.- Command :
echo "Début du build..." npm install npm test
Post-build Actions :
Add post-build action-> Archive the artifacts.- Files to archive :
build/**, *.log
Cliquez sur Save, puis Build Now.
Le "Nouveau" mode (Moderne)
"Pipeline as Code" est la méthode moderne. La configuration n'est plus dans l'UI de Jenkins, mais dans un fichier texte appelé Jenkinsfile, stocké à la racine de votre projet Git.
Avantages
- Versionné : La CI/CD est dans Git, comme le code (traçabilité).
- Reproductible : Il suffit de pointer Jenkins vers le SCM.
- Robuste : Permet une logique complexe (
try/catch, parallèle, conditions). - Partageable : (Via Shared Libraries).
Jenkinsfile (Exemple simple)
pipeline {
agent any // Sur quel agent ?
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}Le Jenkinsfile peut être écrit dans deux syntaxes (basées sur Groovy) :
| Critère | 1. Declarative Pipeline (Recommandé) | 2. Scripted Pipeline (Avancé) |
|---|---|---|
| Syntaxe | Structurée, (similaire à YAML/JSON). | Code Groovy pur. Très flexible. |
| Bloc racine | pipeline { ... } | node { ... } |
| Courbe d'apprentissage | Facile à lire, structurée. | Nécessite de connaître Groovy. |
| Logique complexe | Limitée (script { ... } pour du Groovy). | Illimitée (if, try/catch natifs). |
| Usage | 90% des cas. CI/CD standard. | Logique très complexe, pipelines dynamiques. |
Squelette Jenkinsfile
// (Pas de 'node')
pipeline { // 1. Bloc racine
agent any // 2. Où exécuter ? (n'importe quel agent)
stages { // 3. Le "travail"
stage('Build') { // 4. Une étape (colonne dans Blue Ocean)
steps {
// 5. Commandes à exécuter
echo "Building..."
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Deploy') {
steps {
echo "Deploying..."
}
}
}
}Directives de Pipeline
pipeline {
// 1. Agent: Spécifier un label (défini sur l'Agent)
// agent { label 'linux-docker' }
// (ou un conteneur Docker)
agent {
docker {
image 'node:18-alpine'
args '-v /tmp:/tmp'
}
}
// 2. Tools: Outils définis dans "Manage Jenkins"
tools {
jdk 'jdk17'
maven 'maven3'
}
// 3. Variables d'environnement
environment {
GREETING = "Hello ${env.BRANCH_NAME}"
DB_PASS = credentials('db-password-id')
}
stages { ... }
}Section post (Après les stages)
Permet d'exécuter des étapes à la fin du build (nettoyage, notifications).
pipeline {
agent any
stages { ... }
post {
// S'exécute toujours
always {
echo 'Cleanup...'
deleteDir() // Nettoie le workspace
}
// Si succès
success {
echo 'Build OK !'
slackSend(message: 'Success')
}
// Si échec
failure {
echo 'Build ÉCHOUÉ !'
slackSend(message: 'FAILURE')
}
// Si statut a changé (ex: OK -> ÉCHEC)
changed {
echo 'Statut changé.'
}
}
}steps)Commandes de base (steps)
| Étape | Description |
|---|---|
sh '...' | Exécute un script Shell (Linux/macOS). |
bat '...' | Exécute un script Batch (Windows). |
pwsh '...' | Exécute PowerShell. |
echo '...' | Affiche un message dans le log. |
error '...' | Stoppe le build (statut FAILED). |
deleteDir() | Nettoie le workspace (rm -rf .). |
Étapes de Plugins (Commun)
| Étape | Description (Plugin) |
|---|---|
git '...' | Clone un dépôt (Plugin Git). |
archiveArtifacts '...' | Archive des fichiers (JUnit). |
junit '...' | Publie les résultats de tests. |
docker.build('...') | Build une image (Docker Pipeline). |
withCredentials(...) | Injecte un secret (Credentials Binding). |
stash / unstash | Passe des fichiers entre les 'stages'. |
Exemple de steps
steps {
// 1. Script Shell (Multi-lignes)
sh '''
echo "Préparation..."
echo "Branch: ${env.BRANCH_NAME}"
npm install
'''
// 2. Archiver
archiveArtifacts artifacts: 'build/app.jar', fingerprint: true
// 3. Mettre dans un 'dir'
dir('reports') {
junit 'results.xml'
}
}Syntaxe Groovy
Le pipeline "Scripted" est du code Groovy pur. Il est plus puissant mais plus difficile à lire.
Il commence par node { } (l'équivalent de agent) et les étapes sont des stage { } (fonctions).
Exemple (Scripted)
node('linux') { // 1. Bloc 'node' (agent)
try {
stage('Checkout') {
git 'https://github.com/...'
}
stage('Build & Test') {
// Logique Groovy (boucles, conditions...)
def nodeVersion = "node:18"
docker.image(nodeVersion).inside {
sh 'npm install'
sh 'npm test'
}
}
stage('Parallel Deploy') {
// Exécuter en parallèle
parallel(
staging: {
stage('Deploy Staging') {
echo "Deploying to staging..."
}
},
qa: {
stage('Deploy QA') {
echo "Deploying to QA..."
}
}
)
}
} catch (e) {
// Gérer les erreurs
currentBuild.result = 'FAILURE'
slackSend(message: "Échec: ${e.message}")
throw e
} finally {
// Cleanup
deleteDir()
}
}1 Job par Branche
Un job "Pipeline" simple est lié à une seule branche (ex: main). C'est inutile pour le développement (feature, dev).
Un job "Multibranch Pipeline" scanne un dépôt Git (via Webhook) et crée/supprime automatiquement des jobs Jenkins pour *chaque branche* qui contient un Jenkinsfile.
Création
- New Item -> Multibranch Pipeline.
- Branch Sources : Add Source -> Git.
- Entrez l'URL du dépôt et les Credentials.
- Save.
Exemple de Jenkinsfile (Multibranch)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Deploy Staging') {
// Ne s'exécute que sur la branche 'dev'
when { branch 'dev' }
steps {
echo "Deploying to STAGING..."
}
}
stage('Deploy Prod') {
// Ne s'exécute que sur 'main'
when { branch 'main' }
steps {
// (Attend une approbation manuelle)
input message: "Déployer en PROD ?"
echo "Deploying to PRODUCTION..."
}
}
}
}archiveArtifacts
Stocke des fichiers (ex: .jar, .war, .zip) à la fin du build, pour un téléchargement ou un déploiement ultérieur.
post {
success {
archiveArtifacts artifacts: 'build/libs/*.jar'
}
}stash / unstash
Passe des fichiers entre les stages (surtout si les agents sont différents).
stage('Build') {
agent { label 'build-agent' }
steps {
sh 'npm run build'
stash name: 'dist', includes: 'dist/**'
}
}
stage('Deploy') {
agent { label 'deploy-agent' }
steps {
unstash name: 'dist'
// (Déployer le dossier 'dist')
}
}Gestion des Secrets (Credentials)
⚠️ Ne **jamais** écrire de mots de passe, tokens, ou clés SSH dans un Jenkinsfile.
Utilisez le Credentials Manager (Manage Jenkins -> Credentials) pour stocker les secrets.
Types : "Secret text", "Username with password", "SSH Username with private key".
Utilisation (withCredentials)
Le bloc withCredentials expose le secret (stocké sous un ID, ex: api-key-prod) en tant que variable d'environnement, masquée dans les logs.
stage('Deploy') {
steps {
// [MY_API_KEY] = 'Secret text' (ID: 'api-key-prod')
withCredentials([string(credentialsId: 'api-key-prod', variable: 'MY_API_KEY')]) {
// La variable $MY_API_KEY n'existe que ici
sh 'deploy.sh --key ${env.MY_API_KEY}'
}
}
}Une UI pour les Pipelines
L'interface "classique" de Jenkins est dense et peu adaptée à la visualisation des stages (Build, Test, Deploy) d'un Pipeline.
Blue Ocean est un plugin (souvent installé par défaut) qui offre une interface utilisateur moderne, visuelle et interactive, dédiée aux Pipelines (Multibranch ou non).
Accès : http://jenkins:8080/blue
Visualisation claire des stages (surtout parallel), accès direct aux logs par étape, et ré-exécution d'un stage spécifique.
Squelette Declarative
pipeline {
// 1. Agent (Où ?)
agent any
// agent { label 'linux' }
// agent { docker { image 'node:18' } }
// 2. Outils (Java, Maven, Node...)
tools {
jdk 'jdk17'
}
// 3. Variables d'Environnement
environment {
MY_VAR = "valeur"
SECRET = credentials('mon-secret-id')
}
// 4. Paramètres (Build 'with parameters')
parameters {
string(name: 'VERSION', defaultValue: '1.0', description: 'Version')
booleanParam(name: 'DO_DEPLOY', defaultValue: false)
}
// 5. Triggers
triggers {
cron('H/15 * * * *') // Tous les 15 min
}
// 6. Étapes
stages {
stage('Checkout') {
steps {
git 'https://github.com/...'
}
}
stage('Build & Test') {
when { branch 'main' } // Condition
steps {
sh 'npm install'
sh 'npm test'
}
}
stage('Package') {
steps {
sh 'npm run build'
// Stash pour le prochain stage
stash name: 'dist', includes: 'dist/**'
}
}
}
// 7. Post-Build
post {
always {
junit 'reports/*.xml'
archiveArtifacts 'build/*.zip'
}
failure {
slackSend(message: "ÉCHEC: ${env.JOB_NAME} build ${env.BUILD_NUMBER}")
}
}
}