Pourquoi héberger sa CI/CD avec Jenkins
Une CI hébergée est pratique jusqu'au jour où les builds se multiplient : chaque minute au-delà du quota est facturée, les gros projets attendent leur tour, et les clés de déploiement de vos serveurs sont stockées chez le fournisseur. Jenkins inverse ce modèle. Il tourne sur votre VPS, exécute autant de builds que vos machines le permettent et garde vos identifiants chiffrés chez vous.
C'est aussi l'outil que la plupart des équipes connaissent déjà : un Jenkinsfile se lit sans formation, la documentation est abondante, et presque chaque outil du marché dispose de son plugin Jenkins.
Ce que Jenkins apporte
- Pipelines en code — un Jenkinsfile versionné avec le projet décrit chaque étape, relue en revue de code comme le reste.
- Webhooks Git — GitHub, GitLab, Gitea ou Forgejo déclenchent le build à chaque push ou pull request.
- Multibranch — chaque branche et chaque pull request reçoit son propre pipeline, créé automatiquement.
- Agents de build — les builds s'exécutent sur des machines dédiées, branchées en SSH.
- Plus de 2 000 plugins — Docker, Kubernetes, SonarQube, Slack, rapports de tests JUnit.
- Identifiants chiffrés — clés SSH et jetons injectés dans le pipeline, masqués dans les journaux.
Jenkins face aux autres CI self-hostées
Faites défiler le tableau
| Jenkins | Woodpecker CI | OneDev | |
|---|---|---|---|
| Licence | MIT | Apache-2.0 | MIT |
| Définition du pipeline | Jenkinsfile (Groovy) | YAML | YAML ou éditeur visuel |
| Forge Git intégrée | Non, se branche sur la vôtre | Non, se branche sur la vôtre | Oui |
| Écosystème de plugins | Plus de 2 000 plugins | Plugins sous forme d'images Docker | Fonctions intégrées |
| Idéal pour | Pipelines complexes, équipes existantes | Pipelines simples en conteneurs | Petite équipe voulant tout-en-un |
Prérequis
Un VPS Ubuntu 24.04 avec 2 Go de RAM et 2 vCPU suffit pour le contrôleur ; comptez 4 Go si vos builds tournent sur la même machine. Il faut Docker et le plugin Compose, un nom de domaine (ou un sous-domaine) pointant vers le VPS, et nginx avec un certificat TLS pour le publier en HTTPS. Jenkins doit répondre sur une adresse HTTPS stable : c'est elle que vos dépôts appellent pour les webhooks.
Installer Jenkins avec Docker Compose
Créer le fichier Compose
Ce
docker-compose.ymldémarre Jenkins LTS sur Java 21. Le port n'est publié que sur la boucle locale : seul nginx y accède. Toutes les données (jobs, plugins, identifiants, historique) vivent dans le volumejenkins-home. Le port 50000 des agents entrants n'est pas publié : les agents se branchent en SSH.services: jenkins: image: jenkins/jenkins:2.580.1-lts-jdk21 restart: unless-stopped ports: - "127.0.0.1:8104:8080" environment: JAVA_OPTS: -Djava.awt.headless=true volumes: - jenkins-home:/var/jenkins_home healthcheck: test: ["CMD-SHELL", "curl -fsS -o /dev/null http://localhost:8080/login || exit 1"] interval: 15s retries: 10 start_period: 60s volumes: jenkins-home: {}Démarrer le conteneur
Placez le fichier dans
/opt/jenkins, puis démarrez la stack. Le premier démarrage prend une trentaine de secondes ;docker compose psdoit afficher l'étathealthy.mkdir -p /opt/jenkins && cd /opt/jenkins docker compose up -d docker compose psPublier Jenkins en HTTPS derrière nginx
Dans le bloc
serverde votre domaine, transmettez les en-têtesX-Forwarded-*: sans eux, Jenkins génère des liens en HTTP et signale un reverse proxy mal configuré.location / { proxy_pass http://127.0.0.1:8104; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port 443; }Déverrouiller Jenkins
Ouvrez
https://votre-domaine. Jenkins demande le mot de passe initial écrit dans son volume de données :docker compose exec jenkins cat /var/jenkins_home/secrets/initialAdminPasswordInstallez ensuite les plugins suggérés, créez votre compte administrateur et confirmez l'URL HTTPS de l'instance.
Ne lancez pas les builds sur le contrôleur
Le contrôleur Jenkins détient tous vos identifiants. Un build qui s'y exécute peut les lire. Dans Administrer Jenkins, passez le nombre d'exécuteurs du nœud intégré à 0 et branchez au moins un agent en SSH. Pour la même raison, ne montez pas le socket Docker du VPS dans le conteneur Jenkins : il donnerait à n'importe quel build l'accès root au serveur.
Écrire un premier pipeline
Créez un « Multibranch Pipeline » qui pointe vers votre dépôt, puis ajoutez un Jenkinsfile à la racine. Cet exemple construit et teste chaque branche, et ne déploie que la branche main, sur un agent portant le label linux :
pipeline {
agent { label 'linux' }
stages {
stage('Build') { steps { sh 'make build' } }
stage('Test') { steps { sh 'make test' } }
stage('Deploy') {
when { branch 'main' }
steps { sh './deploy.sh' }
}
}
}Ajoutez enfin un webhook dans votre dépôt vers https://votre-domaine/github-webhook/ pour GitHub, ou vers l'URL donnée par le plugin de votre forge. Chaque push déclenche alors un build.
Identifiants et agents de build
Les clés SSH, jetons d'API et mots de passe de déploiement se rangent dans Administrer Jenkins, Credentials. Jenkins les stocke chiffrés dans son volume et ne les injecte dans un build qu'au moment où une étape les demande, avec withCredentials ou la directive environment d'un Jenkinsfile ; leur valeur est masquée dans les journaux. Donnez à chaque identifiant le périmètre le plus étroit possible : une clé de déploiement par serveur cible, un jeton en lecture seule pour cloner les dépôts.
Pour les agents, le plus simple est un second VPS sur lequel Java et Docker sont installés. Dans Administrer Jenkins, Nodes, ajoutez un nœud permanent avec la méthode de lancement « via SSH », l'adresse du VPS et une clé SSH enregistrée comme identifiant. Donnez-lui un label, par exemple linux, et visez-le dans vos pipelines. Le contrôleur ne fait plus qu'orchestrer, et un build compromis n'a jamais accès à vos autres secrets.
Sauvegarder et mettre à jour Jenkins
Tout l'état de Jenkins vit dans le volume jenkins-home : jobs, configuration, plugins, identifiants chiffrés et historique des builds. Une archive de ce volume suffit à tout restaurer. Arrêtez Jenkins le temps de la copie pour obtenir une archive cohérente :
cd /opt/jenkins
docker compose stop jenkins
docker run --rm -v jenkins_jenkins-home:/data -v \"$PWD\":/backup alpine tar czf /backup/jenkins-home.tar.gz -C /data .
docker compose start jenkinsPour mettre à jour, suivez la ligne LTS, publiée toutes les douze semaines environ avec des correctifs intermédiaires : remplacez le tag de l'image dans le docker-compose.yml, puis lancez docker compose pull et docker compose up -d. Mettez ensuite à jour les plugins depuis Administrer Jenkins, Plugins, et lisez les avis de sécurité publiés par le projet : la plupart des failles corrigées concernent des plugins, pas le cœur.
Dépannage
« It appears that your reverse proxy set up is broken » : nginx ne transmet pas X-Forwarded-Proto ou l'URL de Jenkins n'est pas en HTTPS. Corrigez le bloc location, puis l'URL dans Administrer Jenkins, System.
Le conteneur redémarre en boucle : lisez les journaux. La cause la plus fréquente est un manque de mémoire ; donnez au VPS au moins 2 Go de RAM.
docker compose logs --tail=100 jenkinsLes webhooks n'arrivent pas : vérifiez dans le dépôt l'historique des livraisons du webhook, puis que l'adresse appelée est bien l'URL HTTPS publique de Jenkins.
Installation en un clic depuis le Marketplace ServOrbit
Sur un VPS ServOrbit, Jenkins s'installe depuis le Marketplace : choisissez l'adresse, cliquez sur Installer, et le script déploie Jenkins LTS dans Docker, avec son volume de données et le reverse proxy nginx en HTTPS. Le mot de passe initial d'administration s'affiche dans votre espace client. Pas de domaine ? Le sous-domaine gratuit du VPS suffit, HTTPS compris.