Je vous propose de voir comment profiter des nouveautés de Jenkins2 et docker pour optimiser nos usines logicielles.
Nous aborderons les points suivants:
- Jenkins dans un container
- Build As Code
- Jenkins tools et docker
Avant d’en arriver là, revenons sur les bases
Docker technologie de container
Docker est une technologie de container qui s’appui sur 2 grands principes :
- Une image correspond à un instantané d’une machine (unix/linux) qui a été définit dans un fichier Dockerfile (la recette de construction) et construite une fois pour toute.
- Le container est une instance d’une image qui fait tourner un process de manière complètement isolée des autres au sein d’une machine (physique ou virtuelle) équipée du daemon docker
Lien utile: https://docs.docker.com/engine/getstarted/
Jenkins 2 en mode As Code
Jenkins est très connu en tant qu’outil de build et présente une palette très large de plugins. Malheureusement cette multiplication des plugins, la rétro-compatibilité et la maintenabilité de ceux-ci sont de plus en plus compliquées pour la communauté open-source.
Avec l’arrivée de nouveaux concurrents du cloud qui utilisent la technique du Build-As-Code, Jenkins a décidé de prendre un nouveau virage en créant Jenkins2.
Ce changement apporte entre autre le Build-As-Code appelé Pipeline.
Un pipeline est une définition du process d’intégration continue / livraison continue écrit dans un fichier nommé Jenkinsfile. Cette description est réalisée avec un langage simplifié (DLS) ou en groovy et déposé dans le repository du projet.
L’objectif étant d’avoir un process de CI / CD versionné, reproductible et transportable sur différents Jenkins.
Lien utile: https://jenkins.io/doc/book/pipeline/
Utilisation de docker pour et par Jenkins
L'architecture cible
- 1 machine avec docker pour héberger les Jenkins master (où nous mettrons une restriction d'utilisation)
- N machine en un cluster Docker Swarm pour l’exécution des nodes et tools en container
Jenkins dans un container
Jenkins propose sur le hub docker une version en container de son application.
Ceci présente plusieurs avantages :
- Possibilité de tester rapidement une version
- Il est possible d’étendre cette image pour y spécifier les plugins à installer par défaut et leurs versions (https://github.com/jenkinsci/docker)
Démarrage d’un jenkins :
docker run -p 8080:8080 jenkinsci/jenkins:latest
Si je souhaite persister les fichiers de configuration et les jobs, je rajoute un volume comme ceci :
docker run –p 8080 :8080 –v /mon_rep/local:/var/jenkins_home jenkinsci/jenkins:latest
A partir de maintenant je dispose d’un Jenkins opérationnel.
Vous allez me dire, ça change quoi ?
- Je peux facilement tester des montées de versions
- Revenir sur une version précédente sans perdre mes données
Mais le meilleur est à venir.
Jenkins utilise docker
L'image officielle n'étant pas équipée du client docker, nous allons donc l'ajouter. Pour cela nous allons créer notre fichier Dockerfile qui va étendre l'image officielle.
FROM jenkinsci/jenkins:latest RUN apt-get update \ && apt-get install -y curl ca-certificates \ && curl -s https://get.docker.com/ | sed 's/docker-engine/docker-engine=%%DOCKER_VERSION%%*/' | sh \ && echo 'DOCKER_OPTS="-H :2375 -H unix:///var/run/docker.sock"' >> /etc/default/docker \ && usermod -aG docker jenkins
Reste à builder cette nouvelle image et la lancer :
docker built -t monjenkins . docker run –p 8080:8080 –v /mon_rep/local:/var/jenkins_home /var/jenkins_home monjenkins:latest
Grâce au docker-plugin, nous allons pouvoir instancier des nœuds Jenkins Slave basés sur des images pré-configurées. Ces nouveaux nœuds seront déployés au sein d'un cluster Swarm et pourrons avoir une durée de vie paramétrable.
Pour ce qui est de la configuration du jenkins, suivre ce lien: https://wiki.jenkins-ci.org/display/JENKINS/Docker+Plugin
Ce que qui change par rapport à une usine traditionnelle:
- Remplacement des VM par des images docker
- Mutualisation de plusieurs types de nœuds sur un même pool de ressource CPU / RAM
- Diminution des besoins en ressources CPU / RAM/ Disque
- Environnement éphémère à durée de vie paramétrable
Docker et les Jenkins Tools
Nous allons maintenant nous intéresser au besoin des projets sur les différentes versions des outils. Qui n'a pas eu de problème de conflit de version entre les projets Java, Maven, NPM, Python ou autres?
Jusqu'à hier nous tentions de créer des VM avec un jeux d'outils mutualisés sur un nombre de VM toujours plus grand. Difficile de maintenir ces nombreuses configurations.
Grace à Docker et Jenkins pipelie nous n'avons plus besoin d'installer les Tools sur le Jenkins master ou sur les slave. Jenkins nous permet de lancer des containers docker avec notre Workspace de Job et d'y exécuter nos étapes de build.
En jenkins Pipeline, la définition des étapes se fait au sein d'une closure en paramètre de la méthode inside.
Voici quelques exemples:
Maven
docker.image('maven:3.2').inside { sh "mvn clean install" }
Cette opération peut être reproduite autant de fois qu'on le souhaite pour chacun des tools dont nous avons besoin pour produire notre livrable applicatif.
Les gains sont:
- Facilité d'utiliser une version spécifique d'un tools
- Suppression des VM multi tools et des risques de conflits.
- Autonomie donné au projet sur les choix des versions des tools
En conclusion
Jenkins 2 permet d'avoir une configuration de build versionnée dans un fichier Jenkinsfile sur le repository du projet. Dans sa démarche de rationalisation des plugins et de rendre la main au projet, il est également plus simple de définir du code spécifique au build du projet.
Docker nous apporte une rationalisation des ressources matérielles et une reproductibilité des builds grâce à l'isolement des containers.
Tout ceci nous permet de réduire le nombre de Jenkins master et slave et par la même occasion de reprendre le contrôle sur l'uniformisation des configurations et outils de nos usines logicielles.
docker build -t monjenkins .
et non docker built -t monjenkins .
(un d à la place du t)
Très bon article.