Jenkins
Jenkins est le robot qui teste, construit et déploie. Il tourne sur tm-tooling et s'affiche sur ci.time.jostud.com.
Particularité de cette installation : rien n'est configuré à la main dans l'interface de Jenkins. Utilisateurs, droits, identifiants, jobs : tout vient de fichiers versionnés. Si la machine disparaît, un ansible-playbook recrée un Jenkins identique.
L'image : jenkins/Dockerfile
FROM jenkins/jenkins:lts
USER root
RUN apt-get update && apt-get install -y docker.io python3-pip curl && rm -rf /var/lib/apt/lists/*
COPY jenkins/Plugins/plugins.txt /Plugins/plugins.txt
COPY jenkins/job_dsl.groovy /job_dsl.groovy
RUN jenkins-plugin-cli --plugin-file /Plugins/plugins.txt
RUN mkdir -p /var/jenkins_home/casc_configs && chown -R jenkins:jenkins /var/jenkins_home/casc_configs
USER jenkinsLes plugins sont installés au build de l'image, pas au démarrage : Jenkins démarre avec tout ce qu'il faut.
Les plugins : Plugins/plugins.txt
| Plugin | Rôle |
|---|---|
configuration-as-code | Lire casc.yml |
job-dsl | Créer les jobs depuis job_dsl.groovy |
workflow-aggregator | Les pipelines |
git, git-client, github | Cloner le dépôt |
credentials, credentials-binding | Ranger et utiliser les secrets |
ssh-agent, ssh-slaves | Se connecter en SSH pour déployer |
docker-plugin, docker-workflow, docker-commons | Utiliser Docker dans les pipelines |
role-strategy, matrix-auth | Les droits des utilisateurs |
script-security, structs | Dépendances des autres plugins |
ws-cleanup | Nettoyer l'espace de travail |
pipeline-stage-view, blueocean | Voir les étapes des pipelines dans l'interface |
Le conteneur : jenkins/docker-compose.yml
services:
jenkins:
build:
context: ..
dockerfile: jenkins/Dockerfile
restart: unless-stopped
user: "root"
environment:
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs/casc.yml
env_file:
- .env
container_name: jenkins
ports:
- "${JENKINS_BIND_IP}:8080:8080"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- ./casc.yml:/var/jenkins_home/casc_configs/casc.yml:ro
secrets:
- deploy_key
secrets:
deploy_key:
file: ./secrets/deploy_key| Élément | Explication |
|---|---|
runSetupWizard=false | Pas d'assistant d'installation : la configuration vient de casc.yml |
env_file: .env | Les variables écrites par Ansible (mot de passe admin, jetons, IP de prod...) |
${JENKINS_BIND_IP}:8080:8080 | Jenkins n'écoute que sur l'IP privée 10.132.0.3 |
jenkins_home | Un volume : l'historique des builds survit aux redémarrages |
/var/run/docker.sock | Jenkins pilote le Docker de la machine pour construire les images |
user: "root" | Nécessaire pour utiliser docker.sock |
secrets: deploy_key | La clé SSH privée est montée dans /run/secrets/deploy_key, jamais dans une variable d'environnement |
La configuration : jenkins/casc.yml
Le plugin Configuration as Code (CasC) lit ce fichier au démarrage. Les ${...} sont remplacés par les variables d'environnement du .env.
Le système
jenkins:
systemMessage: "Welcome to Time Manager Jenkins."
numExecutors: 4
globalNodeProperties:
- envVars:
env:
- key: "GHCR_OWNER"
value: "${GHCR_USERNAME}"
- key: "VITE_API_URL"
value: "${VITE_API_URL}"
- key: "PROD_HOST"
value: "${PROD_HOST}"- 4 builds peuvent tourner en même temps.
- Trois variables sont disponibles dans tous les pipelines :
env.GHCR_OWNER,env.VITE_API_URL,env.PROD_HOST.
Les utilisateurs et les droits
securityRealm:
local:
allowsSignup: false
users:
- id: "admin"
password: "${JENKINS_ADMIN_PASSWORD}"
authorizationStrategy:
roleBased:
roles:
global:
- name: "admin"
permissions: ["Overall/Administer"]
entries:
- user: "admin"Un seul compte, admin. Personne ne peut créer de compte (allowsSignup: false). Un visiteur non connecté ne voit rien.
Les identifiants
| ID | Type | Contenu | Utilisé pour |
|---|---|---|---|
github-token | Utilisateur + mot de passe | Compte et jeton GitHub | Cloner le dépôt |
ghcr | Utilisateur + mot de passe | Compte et jeton GitHub | Pousser les images sur ghcr.io |
vm-ssh-key | Clé SSH | Utilisateur deploy, clé lue dans /run/secrets/deploy_key | Se connecter à tm-prod pour déployer |
Les pipelines les utilisent par leur ID, sans jamais voir leur valeur en clair dans les journaux (Jenkins masque les secrets).
Les jobs
jobs:
- file: job_dsl.groovyCasC exécute job_dsl.groovy, qui crée les jobs.
Les jobs : jenkins/job_dsl.groovy
folder('TimeManager') {
description('Time Manager build and deployment jobs.')
}
pipelineJob('TimeManager/frontend') {
triggers {
scm('H/2 * * * *')
}
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/Epitech2026-2027/I-DEV-700-INT-7-1-timemanager-21.git')
credentials('github-token')
}
branches('*/main')
extensions {
pathRestriction {
includedRegions('timemanager-web/.*\ntimemanager-devops/jenkins/pipelines/frontend.groovy')
}
}
}
}
scriptPath('timemanager-devops/jenkins/pipelines/frontend.groovy')
}
}
}Le job TimeManager/backend est identique, avec timemanager-api/ et backend.groovy. Le job TimeManager/docs aussi, avec timemanager-docs/, docs/database.mmd et docs.groovy.
| Élément | Sens |
|---|---|
folder('TimeManager') | Un dossier qui regroupe les jobs |
scm('H/2 * * * *') | Toutes les 2 minutes, regarder s'il y a de nouveaux commits. H étale les vérifications pour ne pas tout lancer à la même seconde. |
branches('*/main') | Seulement la branche main |
pathRestriction | Ne lancer le job que si un fichier de ces chemins a changé. Un commit qui ne touche que le mobile ne relance rien. |
scriptPath | Le pipeline à exécuter est dans le dépôt, à ce chemin |
Le pipeline vit dans le dépôt
Le contenu du pipeline n'est pas dans Jenkins mais dans pipelines/*.groovy, versionné avec le code. Modifier ce fichier dans main relance d'ailleurs le pipeline (il est dans includedRegions).
Pourquoi interroger GitHub plutôt qu'un webhook
Le dépôt appartient à une organisation de l'école dans laquelle l'équipe n'a pas les droits d'administration. Les webhooks (GitHub qui prévient Jenkins à chaque commit) et les clés de déploiement ne sont donc pas disponibles. Jenkins interroge le dépôt à la place :
- toutes les deux minutes, chaque job regarde le dernier commit de
main; - le filtre
pathRestrictionne déclenche un job que si son code a changé :timemanager-web/pour le frontend,timemanager-api/pour le backend, plus le fichier de pipeline de chaque job.
L'interrogation n'a besoin que d'un accès en lecture, et GitHub n'a jamais besoin de joindre Jenkins.
Se connecter
ci.time.jostud.com, compte admin, mot de passe jenkins_admin_password du vault group_vars/tooling.yml :
cd timemanager-devops/ansible
ansible-vault view group_vars/tooling.ymlSans connexion, Jenkins répond 403 et n'affiche rien. Les liens directs vers chaque pipeline et ce qu'on y trouve sont dans Pipelines CI/CD.
Par un tunnel SSH
Si le domaine ne répond pas, on peut joindre Jenkins directement par un tunnel SSH vers tm-tooling :
ssh -N -L 8080:10.132.0.3:8080 eliashounnou@34.156.3.169puis ouvrir http://localhost:8080. Le tunnel reste ouvert tant que la commande tourne.