Tutoriel : Déploiement de Jenkins via Docker Compose avec pipeline .NET Core 8, publication et déploiement d'image dans une registry locale

Ce tutoriel décrit comment mettre en place une instance Jenkins dans un conteneur Docker (via Docker Compose) et configurer un pipeline Jenkins qui :

  1. Exécute les étapes de build (restore, build, test) pour une application .NET Core 8 dans des conteneurs Docker éphémères.
  2. Construit l'image Docker de l'application à partir d'un Dockerfile présent dans le projet, la tague et la pousse dans une registry locale (192.168.1.200:5000).
  3. Déploie ensuite cette image sur l'hôte en lançant un conteneur et en affichant dans la console Jenkins des informations sur le container déployé.

La bonne pratique adoptée ici consiste à organiser les Dockerfiles dans des sous-répertoires afin d’isoler les contextes de build.


1. Prérequis


2. Organisation du projet

La structure recommandée du projet est la suivante :

project-root/
├── jenkins/
│   └── Dockerfile         # Dockerfile pour l'image Jenkins personnalisée
├── Jenkinsfile            # Pipeline Jenkins pour build, publication et déploiement
├── Dockerfile             # Dockerfile de votre application (pour construire l'image applicative)
└── docker-compose.yml     # Fichier Docker Compose pour builder et déployer Jenkins

Remarque : Vous pouvez adapter l’arborescence selon vos préférences (par exemple, placer le Dockerfile de l’application dans un sous-répertoire dédié).


3. Création de l'image Jenkins personnalisée

Dans le répertoire jenkins/, créez le fichier Dockerfile suivant :

# jenkins/Dockerfile

# Utilisation de l'image officielle Jenkins LTS
FROM jenkins/jenkins:lts

# Passage en mode root pour installer des packages
USER root

# Installation des paquets nécessaires et configuration du dépôt Docker
RUN apt-get update && \
    apt-get install -y ca-certificates curl gnupg2 lsb-release apt-transport-https software-properties-common && \
    install -m 0755 -d /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \
    chmod a+r /etc/apt/keyrings/docker.asc && \
    . /etc/os-release && \
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $VERSION_CODENAME stable" \
      | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt-get update && \
    apt-get install -y docker-ce-cli && \
    rm -rf /var/lib/apt/lists/*

# Ajout du groupe Docker et ajout de l'utilisateur Jenkins à ce groupe.
# Remplacez 999 par le GID obtenu via : stat -c '%g' /var/run/docker.sock sur votre hôte.
ARG DOCKER_GID=999
RUN groupadd -for -g ${DOCKER_GID} docker && usermod -aG docker jenkins

# Retour à l'utilisateur Jenkins
USER jenkins

Explications :


4. Déploiement via Docker Compose

Créez le fichier docker-compose.yml à la racine du projet :

version: '3.8'

services:
  jenkins:
    build:
      context: ./jenkins
      dockerfile: Dockerfile
      args:
        DOCKER_GID: 999  # Remplacez 999 par le GID obtenu sur votre système
    container_name: jenkins-master
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - jenkins_home:/var/jenkins_home

volumes:
  jenkins_home:

Note :
L'accès au socket Docker est géré directement dans l'image Jenkins grâce au Dockerfile, il n'est donc pas nécessaire d'utiliser l'option group_add ici.

Lancez Jenkins avec la commande :

docker-compose up -d

5. Configuration du plugin Docker Pipeline dans Jenkins

  1. Accédez à l'interface Jenkins via http://localhost:8080.
  2. Récupérez le mot de passe initial (situé dans /var/jenkins_home/secrets/initialAdminPassword ou affiché dans les logs).
  3. Installez le plugin Docker Pipeline via Manage Jenkins → Manage Plugins.

6. Création du pipeline Jenkins pour .NET Core 8, publication et déploiement

Créez le fichier Jenkinsfile à la racine du projet avec le contenu suivant :

pipeline {
    agent none
    stages {
        stage('Restore') {
            agent {
                docker {
                    image 'mcr.microsoft.com/dotnet/sdk:8.0'
                    // Passage de l'environnement HOME vers un dossier accessible pour éviter l'erreur de permission
                    args '-e HOME=/tmp'
                    // Exécution dans un conteneur propre
                    reuseNode false
                }
            }
            steps {
                sh 'dotnet restore'
            }
        }
        stage('Build') {
            agent {
                docker {
                    image 'mcr.microsoft.com/dotnet/sdk:8.0'
                    args '-e HOME=/tmp'
                    reuseNode false
                }
            }
            steps {
                sh 'dotnet build --configuration Release'
            }
        }
        stage('Test') {
            agent {
                docker {
                    image 'mcr.microsoft.com/dotnet/sdk:8.0'
                    args '-e HOME=/tmp'
                    reuseNode false
                }
            }
            steps {
                sh 'dotnet test --no-build --verbosity normal'
            }
        }
        stage('Publish') {
            agent {
                // Utilisation d'une image Docker officielle disposant du client Docker
                docker {
                    image 'docker:20.10'
                    // Montage du socket Docker et exécution en tant que root pour accéder aux privilèges
                    args '-v /var/run/docker.sock:/var/run/docker.sock -u 0'
                    // Utilisation du workspace courant afin d'accéder au Dockerfile et aux sources
                    reuseNode true
                }
            }
            steps {
                script {
                    // Définir le nom de l'image locale et le tag pour la registry
                    def imageName = "recupufolep:latest"
                    def registryImage = "192.168.1.200:5000/recupufolep:latest"
                    
                    // Construction de l'image à partir du Dockerfile présent dans le workspace
                    sh "docker build -t ${imageName} ."
                    
                    // Tag de l'image pour la registry locale
                    sh "docker tag ${imageName} ${registryImage}"
                    
                    // Poussée de l'image dans la registry locale
                    sh "docker push ${registryImage}"
                }
            }
        }
        stage('Deploy') {
            agent {
                docker {
                    image 'docker:20.10'
                    // Montage du socket Docker et exécution en tant que root pour accéder aux privilèges
                    args '-v /var/run/docker.sock:/var/run/docker.sock -u 0'
                    reuseNode true
                }
            }
            steps {
                script {
                    def registryImage = "192.168.1.200:5000/recupufolep:latest"
                    
                    // Suppression du conteneur existant (s'il existe déjà)
                    sh "docker rm -f recupufolep_container || true"
                    
                    // Lancement du conteneur en détaché, mappant par exemple le port 8081 de l'hôte au port 80 du container
                    def containerId = sh(script: "docker run -d --name recupufolep_container -p 8081:80 ${registryImage}", returnStdout: true).trim()
                    
                    echo "Container lancé, ID : ${containerId}"
                    
                    // Récupération et affichage des informations du conteneur
                    def containerInfo = sh(script: "docker inspect ${containerId}", returnStdout: true).trim()
                    echo "Infos du container : ${containerInfo}"
                }
            }
        }
    }
}

Détails techniques :


7. Déploiement et validation du pipeline

  1. Création du job Pipeline :

    • Dans Jenkins, créez un nouveau job de type Pipeline.
    • Configurez-le pour pointer vers votre dépôt Git contenant le Jenkinsfile ou copiez directement le script dans l'éditeur du pipeline.
  2. Exécution et vérification :

    • Lancez le pipeline.
    • Vérifiez que les étapes Restore, Build et Test s'exécutent correctement dans des conteneurs .NET Core 8 isolés sans erreur de permission.
    • Dans le stage Publish, l'image de l'application est construite, taguée et poussée dans la registry locale (192.168.1.200:5000).
    • Dans le stage Deploy, l'image est lancée sur l'hôte et les informations du conteneur (ID, détails via inspect) sont affichées dans la console Jenkins.

8. Références techniques


Ce tutoriel complet vous permet de :

Vous pouvez désormais publier ce tutoriel. N'hésitez pas à revenir pour toute question ou précision supplémentaire.