Jenkins Jobs & Pipelines — Jenkinsfile
Un Pipeline Jenkins automatise toutes les étapes du CI/CD dans un fichier de code versionné dans Git.
Types de Jobs Jenkins
| Type | Description | Cas d'usage |
|---|---|---|
| Freestyle Project | Configuration via UI uniquement | Scripts simples, tâches basiques |
| Pipeline | Script Jenkinsfile, multi-étapes | CI/CD complet, recommandé |
| Multibranch Pipeline | Pipeline par branche Git | Feature branches, PR automatiques |
| Organization Folder | Scan auto des repos GitHub/GitLab | Grandes organisations |
Recommandation : utiliser Pipeline ou Multibranch Pipeline pour tout CI/CD sérieux.
Pipeline as Code
Pourquoi Pipeline as Code ?
| Configuration UI (Freestyle) | Pipeline as Code (Jenkinsfile) |
|---|---|
| Configuration dans l'interface Jenkins | Configuration dans un fichier texte |
| Non versionné dans Git | Commité avec le code source |
| Difficile à auditer | Historique Git complet |
| Risque de perte de config | Reproductible et portable |
| Pas de code review | Review possible comme le code |
"Everything as Code" — best practice DevOps : versionner la configuration comme le code.
Principe
Code source
+
Jenkinsfile ──► git commit ──► Git repo
│
▼ webhook trigger
Jenkins lit le Jenkinsfile
et exécute le pipeline
Jenkinsfile — Syntaxes
2 syntaxes disponibles
| Declarative | Scripted | |
|---|---|---|
| Syntaxe | Structure prédéfinie, YAML-like | Groovy pur, libre |
| Facilité | Plus simple à lire/écrire | Plus complexe |
| Flexibilité | Moins flexible | Très flexible |
| Recommandé | ✅ Oui (débutants et équipes) | Pour cas avancés |
Jenkinsfile Declaratif — Structure de Base
pipeline {
agent any // Où s'exécute le pipeline
environment { // Variables d'environnement globales
APP_NAME = "mon-app"
REGISTRY = "docker.io/moncompte"
}
stages {
stage('Build') { // Étape 1 : Build
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Test') { // Étape 2 : Tests
steps {
sh 'npm test'
}
}
stage('Docker Build') { // Étape 3 : Image Docker
steps {
sh "docker build -t ${APP_NAME}:${BUILD_NUMBER} ."
}
}
stage('Push') { // Étape 4 : Push registry
steps {
withCredentials([usernamePassword(
credentialsId: 'docker-hub',
usernameVariable: 'USER',
passwordVariable: 'PASS'
)]) {
sh "docker login -u $USER -p $PASS"
sh "docker push ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER}"
}
}
}
stage('Deploy') { // Étape 5 : Déploiement
steps {
sh "ssh user@server 'docker pull ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER}'"
sh "ssh user@server 'docker run -d -p 3000:3000 ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER}'"
}
}
}
post { // Actions après le pipeline
success {
echo 'Pipeline réussi !'
}
failure {
echo 'Pipeline échoué !'
// slackSend channel: '#devops', message: "Build ${BUILD_NUMBER} failed"
}
}
}
Champs obligatoires
| Bloc | Rôle | Valeurs courantes |
|---|---|---|
pipeline | Bloc racine obligatoire | — |
agent | Où s'exécute le pipeline | any, none, docker, label agent |
stages | Conteneur de toutes les étapes | — |
stage('Nom') | Une étape nommée | Nom libre |
steps | Commandes à exécuter dans l'étape | sh, echo, script, etc. |
Directives Clés
agent — Exécuteur
agent any // N'importe quel agent disponible
agent none // Pas d'agent global (défini par stage)
agent { label 'linux' } // Agent avec ce label
agent { // Docker comme agent d'exécution
docker { image 'node:18-alpine' }
}
environment — Variables
environment {
BUILD_NUMBER = "${env.BUILD_NUMBER}" // Variables Jenkins intégrées
BRANCH_NAME = "${env.BRANCH_NAME}"
DOCKER_TAG = "1.0.${BUILD_NUMBER}"
}
Variables Jenkins intégrées utiles :
| Variable | Valeur |
|---|---|
BUILD_NUMBER | Numéro du build (1, 2, 3...) |
BRANCH_NAME | Nom de la branche Git |
GIT_COMMIT | Hash du commit |
WORKSPACE | Chemin du workspace Jenkins |
JOB_NAME | Nom du job Jenkins |
when — Conditions
stage('Deploy Production') {
when {
branch 'main' // Seulement sur la branche main
}
steps {
sh './deploy.sh prod'
}
}
stage('Deploy Staging') {
when {
branch 'develop'
}
steps {
sh './deploy.sh staging'
}
}
post — Actions post-build
post {
always { echo 'Toujours exécuté' }
success { echo 'Build réussi' }
failure { echo 'Build échoué' }
unstable { echo 'Build instable (tests failed)' }
changed { echo 'Statut différent du build précédent' }
}
Triggers Automatiques
pipeline {
triggers {
pollSCM('H/5 * * * *') // Vérifier Git toutes les 5 min
cron('H 2 * * 1-5') // Déclenchement planifié (lun-ven 2h)
}
// ...
}
Méthode recommandée : Webhooks Git
- GitHub/GitLab envoie un événement à Jenkins à chaque push
- Déclenche le build immédiatement (pas de polling)
- Configurer dans les settings du repo Git : URL Jenkins + secret token
Multibranch Pipeline
Pour créer automatiquement un pipeline par branche Git :
Repo Git
├── main → Pipeline "main" (build + deploy prod)
├── develop → Pipeline "develop" (build + deploy staging)
├── feature/x → Pipeline "feature/x" (build + tests only)
└── feature/y → Pipeline "feature/y" (build + tests only)
Jenkins scanne le repository, détecte les branches contenant un Jenkinsfile, et crée un pipeline automatiquement pour chacune.
Configuration : New Item → Multibranch Pipeline → Branch Sources (GitHub/GitLab) + Credentials.
Exemple Complet — Application Java avec Maven
pipeline {
agent any
tools {
maven 'Maven-3.9' // Outil configuré dans Manage Jenkins → Tools
jdk 'JDK-17'
}
stages {
stage('Checkout') {
steps {
git branch: 'main',
credentialsId: 'git-credentials',
url: 'https://github.com/mon-org/mon-app.git'
}
}
stage('Build & Test') {
steps {
sh 'mvn clean package'
}
post {
always {
junit 'target/surefire-reports/**/*.xml' // Rapport tests
}
}
}
stage('Build Docker Image') {
steps {
sh "docker build -t mon-app:${BUILD_NUMBER} ."
}
}
stage('Push to Nexus') {
steps {
nexusArtifactUploader(
nexusVersion: 'nexus3',
protocol: 'http',
nexusUrl: 'nexus:8081',
groupId: 'com.example',
artifactId: 'mon-app',
version: "1.0.${BUILD_NUMBER}",
repository: 'maven-releases',
credentialsId: 'nexus-credentials',
artifacts: [[ artifactId: 'mon-app', file: 'target/mon-app.jar', type: 'jar' ]]
)
}
}
}
}
Jenkinsfile Scripté (référence)
// Syntaxe Scriptée — Groovy pur
node {
stage('Build') {
sh 'npm install'
sh 'npm run build'
}
stage('Test') {
sh 'npm test'
}
stage('Deploy') {
if (env.BRANCH_NAME == 'main') {
sh './deploy.sh'
}
}
}
Même logique que le Declaratif, mais sans la structure imposée — plus de liberté Groovy.
À retenir
- Freestyle = config UI uniquement → éviter pour le CI/CD
- Pipeline = Jenkinsfile dans Git → recommandé
- Multibranch = un pipeline par branche Git → idéal pour feature branches
- Jenkinsfile Declaratif :
pipeline→agent→stages→stage→stepsenvironment= variables,when= conditions,post= actions après le build- Variables Jenkins :
BUILD_NUMBER,BRANCH_NAME,GIT_COMMIT- Triggers : webhooks Git (push) → plus réactif que
pollSCMwithCredentials= utiliser les secrets stockés dans Jenkins sans les exposer