Jenkins
Jenkins est un outil open source d’automatisation des processus de développement logiciel (CI/CD).
Il permet de :
- Automatiser les builds, tests et déploiements.
- Intégrer en continu (CI) les modifications du code.
- Livrer en continu (CD) des applications en production.
Fonctionnalités Clés
Intégration Continue (CI) : Exécute des tests à chaque commit.
Pipelines as Code : Définition des workflows via des fichiers Jenkinsfile.
Plugins (1 800+) : Compatible avec Git, Docker, Kubernetes, AWS, etc.
Scalabilité : Fonctionne avec des agents (maître/esclaves).
Pourquoi utiliser Jenkins ?
- Réduction des erreurs : Moins d’interventions manuelles.
- Gain de temps : Automatisation des tâches répétitives.
- Flexibilité : Supporte tous les langages (Java, Python, Go…).
Cas d’Usage
- Déploiement d’une app Java : Build → Tests → Déploiement sur Tomcat.
- DevOps/Cloud : Intégration avec Docker, Kubernetes, Terraform.
Installation
vous pouvez utiliser le compose suivant :
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
volumes:
- jenkins_home:/var/jenkins_home
restart: always
ssh-agent:
image: jenkins/ssh-agent
restart: always
volumes:
jenkins_home:
Utilisation
Il vous faudra installer les plug-in pour ansible,terraform, etc ... puis créer votre pipeline
Dans cet exemple j'ai un serveur avec jenkins et un autre avec ansible et terraform installé qui vont éxécuter le pipeline qui consiste a mettre a jour tous les serveurs.
Il faut ajouter le noeud ansible, pour cela veiller a faire l'échange de clé de votre jenkins vers votre ansible.
Voici un exemple de script jenkins a modifier a votre convenance :
pipeline {
agent any
triggers {
cron('H 2 * * *') // Ce cron lance le pipeline tous les jours à 2h00 du matin
}
environment {
ANSIBLE_HOST = "10.15.1.190" // Adresse de ton serveur Ansible
PLAYBOOK_PATH = "/root/maj.yml" // Chemin vers ton playbook
INVENTORY_PATH = "/etc/ansible/inventory" // Le chemin vers ton fichier d'inventaire Ansible
}
stages {
stage('Exécuter le Playbook') {
steps {
script {
// Exécution du playbook Ansible
sh """
ansible all -m shell -a "apt-get update && apt-get upgrade -y" -b
"""
}
}
}
}
post {
success {
echo "Playbook exécuté avec succès!"
}
failure {
echo "Échec de l'exécution du playbook."
}
}
}
Ce pipeline lancera la commande apt-get update && apt-get upgrade -y tous les jours a 2h du matin et nous pourrons voir si tout c'est bien dérouler et quels sont les modifications (la fin du script est trompeuse car je n'utilise pas de playbook ansible mais seulement une commande, j'utilise cette méthode car lors de l'utilisation de playbook je ne voit pas les paquets modifiés).
Voici la sortie :
Started by timer [Pipeline] Start of Pipeline [Pipeline] node Running on ansible in /root/workspace/mise a jour des serveurs [Pipeline] { [Pipeline] withEnv [Pipeline] { [Pipeline] stage [Pipeline] { (Exécuter le Playbook) [Pipeline] script [Pipeline] { [Pipeline] sh + ansible all -m shell -a apt-get update && apt-get upgrade -y -b docker-lab | CHANGED | rc=0 >> Hit:1 http://deb.debian.org/debian bookworm InRelease Get:2 http://security.debian.org bookworm-security InRelease [48.0 kB] Get:3 http://deb.debian.org/debian bookworm-updates InRelease [55.4 kB] Hit:4 https://download.docker.com/linux/debian bookworm InRelease Fetched 103 kB in 0s (234 kB/s) Reading package lists... Reading package lists... Building dependency tree... Reading state information... Calculating upgrade... 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. wazuh | CHANGED | rc=0 >> Réception de :1 http://security.debian.org/debian-security bookworm-security InRelease [48,0 kB] Atteint :2 http://deb.debian.org/debian bookworm InRelease Réception de :3 http://deb.debian.org/debian bookworm-updates InRelease [55,4 kB] 103 ko réceptionnés en 0s (461 ko/s) Lecture des listes de paquets… Lecture des listes de paquets… Construction de l'arbre des dépendances… Lecture des informations d'état… Calcul de la mise à jour… 0 mis à jour, 0 nouvellement installés, 0 à enlever et 0 non mis à jour.
edo | CHANGED | rc=0 >> Atteint :1 http://deb.debian.org/debian bookworm InRelease Atteint :2 http://security.debian.org/debian-security bookworm-security InRelease Atteint :3 http://deb.debian.org/debian bookworm-updates InRelease Ign :4 https://nightly.odoo.com/17.0/nightly/deb ./ InRelease Atteint :5 https://nightly.odoo.com/17.0/nightly/deb ./ Release Lecture des listes de paquets… Lecture des listes de paquets… Construction de l'arbre des dépendances… Lecture des informations d'état… Calcul de la mise à jour… Les paquets suivants seront mis à jour : odoo 1 mis à jour, 0 nouvellement installés, 0 à enlever et 0 non mis à jour. Il est nécessaire de prendre 212 Mo dans les archives. Après cette opération, 14,3 ko d'espace disque supplémentaires seront utilisés. Réception de :1 https://nightly.odoo.com/17.0/nightly/deb ./ odoo 17.0.20250419 [212 MB] apt-listchanges : Lecture des fichiers de modifications (« changelog »)... 212 Mo réceptionnés en 19s (11,2 Mo/s) (Lecture de la base de données... (Lecture de la base de données... 5% (Lecture de la base de données... 10% (Lecture de la base de données... 15% (Lecture de la base de données... 20% (Lecture de la base de données... 25% (Lecture de la base de données... 30% (Lecture de la base de données... 35% (Lecture de la base de données... 40% (Lecture de la base de données... 45% (Lecture de la base de données... 50% (Lecture de la base de données... 55% (Lecture de la base de données... 60% (Lecture de la base de données... 65% (Lecture de la base de données... 70% (Lecture de la base de données... 75% (Lecture de la base de données... 80% (Lecture de la base de données... 85% (Lecture de la base de données... 90% (Lecture de la base de données... 95% (Lecture de la base de données... 100% (Lecture de la base de données... 104577 fichiers et répertoires déjà installés.) Préparation du dépaquetage de .../odoo_17.0.20250419_all.deb ... Dépaquetage de odoo (17.0.20250419) sur (17.0.20250418) ... [Pipeline] } [Pipeline] // script [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Declarative: Post Actions) [Pipeline] echo Playbook exécuté avec succès! [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // withEnv [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS
Un pipeline peut aussi être utiliser pour programmer plusieurs actions, par exemple aller chercher un code dans github ou gitlab puis l'utiliser pour build et déployer un conteneur dans docker, tout cela en utilisant des variables et quelques vérifications .
Voici le script qui sera bien sur a modifier avec vos ip et chemins :
pipeline {
agent any
parameters {
string(name: 'CONTAINER_NAME', defaultValue: 'ubuntu-container', description: 'Nom du conteneur Docker')
string(name: 'NGINX_PORT', defaultValue: '8080', description: 'Port Nginx du conteneur')
}
environment {
DOCKER_HOST = "10.15.1.102" // Machine Docker où se trouvent les conteneurs
GIT_REPO = "http://10.15.1.102:32769/root/docker-ubuntu.git" // URL du dépôt Git
WORKSPACE_DIR = "/root/docker-ubuntu" // Répertoire de travail
IMAGE_NAME = "ubuntu-nginx" // Nom de l'image Docker à créer
}
stages {
stage('Vérification du nom du conteneur') {
steps {
script {
def containerName = params.CONTAINER_NAME
def containerExists = true
while (containerExists) {
containerExists = sh(script: "ssh root@${DOCKER_HOST} 'docker ps -a --filter name=${containerName} -q'", returnStdout: true).trim()
if (containerExists) {
echo "Le conteneur ${containerName} existe déjà."
// Demander un nouveau nom et mettre à jour directement la variable
containerName = input message: "Le conteneur ${containerName} existe déjà. Choisissez un nouveau nom pour le conteneur", parameters: [string(defaultValue: containerName, description: 'Nom du conteneur Docker', name: 'CONTAINER_NAME')]
}
}
echo "Nom du conteneur validé : ${containerName}"
// Mettre à jour la valeur de CONTAINER_NAME
currentBuild.description = "Conteneur nommé : ${containerName}" // Ajouter une description
env.CONTAINER_NAME = containerName // Mise à jour de l'environnement
}
}
}
stage('Vérification du port') {
steps {
script {
def nginxPort = params.NGINX_PORT
def portUsed = true
while (portUsed) {
// Correction du filtre pour vérifier si le port est utilisé
portUsed = sh(script: "ssh root@${DOCKER_HOST} 'docker ps --filter \"publish=${nginxPort}\" -q'", returnStdout: true).trim()
if (portUsed) {
echo "Le port ${nginxPort} est déjà utilisé."
// Demander un nouveau port et mettre à jour directement la variable
nginxPort = input message: "Le port ${nginxPort} est déjà utilisé. Choisissez un nouveau port pour Nginx", parameters: [string(defaultValue: nginxPort, description: 'Port Nginx du conteneur', name: 'NGINX_PORT')]
}
}
echo "Port validé : ${nginxPort}"
// Mettre à jour la valeur du port dans l'environnement
env.NGINX_PORT = nginxPort // Mise à jour de l'environnement
}
}
}
stage('Connexion SSH à la Machine Docker') {
steps {
script {
sh """
# Se connecter à la machine Docker
ssh root@${DOCKER_HOST} 'echo "Connexion SSH réussie !"'
"""
}
}
}
stage('Git Clone sur la Machine Docker') {
steps {
script {
sh """
# Effectuer le git clone
ssh root@${DOCKER_HOST} "
if [ ! -d '${WORKSPACE_DIR}' ]; then
git clone ${GIT_REPO} ${WORKSPACE_DIR}
else
cd ${WORKSPACE_DIR} && git pull
fi
"
"""
}
}
}
stage('Build Docker Image') {
steps {
script {
sh """
# Construire l'image Docker sur la machine Docker
ssh root@${DOCKER_HOST} "
docker build -t ${IMAGE_NAME} ${WORKSPACE_DIR}
"
"""
}
}
}
stage('Run Docker Container') {
steps {
script {
sh """
# Lancer le conteneur Docker à partir de l'image construite
ssh root@${DOCKER_HOST} "
docker run -d -p ${env.NGINX_PORT}:80 --name ${env.CONTAINER_NAME} ${IMAGE_NAME}
"
"""
}
}
}
}
post {
success {
echo "Le conteneur ${env.CONTAINER_NAME} avec Nginx est déployé avec succès sur le port ${env.NGINX_PORT} !"
}
failure {
echo "Une erreur est survenue lors du déploiement. Veuillez vérifier les paramètres et réessayer."
}
}
}
voici le docker file si vous voulez tester :
FROM ubuntu:latest
# Mise à jour du système et installation de Nginx
RUN apt update && apt install -y nginx && \
apt clean && rm -rf /var/lib/apt/lists/*
# Exposer le port 80
EXPOSE 80
# Démarrer Nginx en mode foreground pour que le conteneur reste en vie
CMD ["nginx", "-g", "daemon off;"]
Résultat