Jenkins X : Les Projets
Dans notre article Jenkins X : Installation, nous avions découvert puis installé Jenkins X sur un cluster Kubernetes qui devait nous permettre de contrôler comment nos applications sont déployées sur différents environnements dans un contexte de livraison continue.
Nous avions également vu comment nous créer simplement un projet qui sera automatiquement construit et déployé par notre cluster sur les différents environnements via l'utilisation de quickstarts.
Mais comment cela fonctionne-t-il exactement ? Comment Jenkins X sait-il qu'un projet doit être construit via une commande Maven, qu'une application Flutter doit être livrée sur le Play Store et non sur un Nexus ou encore qu'une librairie ne doit pas être déployée, mais seulement stockée ?
Avant de rentrer dans le vif du sujet, voici un petit rappel de vocabulaire !
Vocabulaire
Docker
Docker est une solution permettant la 'containerisation' d'applications sous forme d'images qui peuvent être déployées sur n'importe quel conteneur.
Image
Une image Docker est un fichier décrivant un système de fichier sans les processus. Ce fichier est utilisé par les conteneurs pour reproduire le système cible avec les applications et la configuration nécessaire.
Dockerfile
Un fichier Dockerfile est un fichier d'instructions permettant la création d'images Docker. Dedans, on y trouve l'image Docker à étendre pour créer la notre, les commandes d'installation des outils, les commandes à exécuter au lancement d'une image Docker dans un conteneur, etc.
Kubernetes
Kubernetes est un orchestrateur de conteneurs Docker facilitant le déploiement, l'agencement, le monitoring et la configuration d'images Docker.
Deploiement
Dans Kubernetes, un déploiement est un descriptif d'une application à déployer. On trouve entre autres dans ce fichier une référence à l'image ou aux images Docker à utiliser, une liste des ports à exposer sur le réseau, les volumes à monter, les variables d'environnement à utiliser, etc.
Pod
Un pod est un groupe d'un ou plusieurs conteneurs modélisant un 'hôte logique' pour une application donnée. Les conteneurs d’un pod partagent une adresse IP et un espace de ports ainsi que des volumes partagés et peuvent communiquer via localhost.
Cette modélisation est créée à partir d'un fichier de déploiement.
Secret
Un secret, comme son nom l'indique, est une donnée chiffrée accessible à la demande au sein du cluster. Un secret est en général utilisé en étant injecté dans les variables d'environnement des conteneurs déployés.
Service
Dans Kubernetes, un service est un descriptif permettant l'exposition des différents pods sur le réseau du cluster. Ce sont ces fichiers qui permettent de configurer un équilibrage de charge automatique pour l'ensemble des pods d'un déploiement.
Ingress
Ingress est un descriptif permettant de configurer l'accès externe aux services du cluster. Ingress peut fournir également de l'équilibrage de charge, le chiffrement et le déchiffrement SSL/TLS, etc.
Helm
Helm est le gestionnaire de packages pour Kubernetes. Comme npm pour Node, Helm permet l'installation et la mise à jour de groupes de ressources pré-configurées, mais sur un cluster Kubernetes.
Chart
Une chart est un ensemble de fichiers templates permettant, en fonction d'éléments de configuration externes comme des secret ou de l'environnement, de décrire un ensemble de ressources Kubernetes à déployer conjointement.
Par exemple, une chart peut contenir un fichier de déploiement et un fichier de service qui permettent à Helm de déployer une application et de mettre à jour le réseau du cluster en conséquence par une action unique.
ChartMuseum
ChartMuseum est une application permettant l'hébergement de Charts Helm, une sorte de Nexus pour Helm si vous voulez !
Skaffold
Skaffold est un outil permettant la construction incrémentale et la sauvegarde de Charts dans des services externes comme ChartMuseum
Les bases d'un projet
Revenons maintenant à notre projet Spring Boot créé précedemment :
Lors de la création ou de l'import d'un projet dans Jenkins X, Jenkins X créer un ensemble de fichiers permettant la configuration des compilations, livraisons et déploiements :
1. Charts
Le répertoire charts généré par Jenkins X contient les fichiers de description des charts Helm.
Habituellement, vous trouverez deux dossiers :
nom de projet (test-jenkins-x) :
Il contient le template de déploiement de notre application pour les environnements de staging et de production.
preview :
le dossier preview contient la description de la chart utilisée pour déployer un environnement temporaire d'acceptance de fonctionnalité (aussi appelé environnement de preview)
Ces dossiers peuvent chacun être séparés en deux :
le dossier templates :
Le dossier templates contient principalement les templates Mustache des fichiers de description de ressources Kubernetes.
Notre projet ne possède ici qu'une description de déploiement et un service pour pouvoir exposer notre application sur le réseau du cluster et à l'extérieur.
Un fichier supplémentaire _helpers.tpl vient s'ajouter à nos descriptifs de ressources, permettant de déclarer des variables globales Mustache à partir des valeurs fournies en entrées.
la racine :
A la racine, vous trouverez trois fichiers donnant des précisions sur la Chart elle-même :
- Chart.yaml → contient des informations de licence de votre CHart
- requirements.yaml (optionnel)→ contient les dépendances de votre Chart vers d'autres Charts. L'environnement de preview dépend par exemple de la Chart principale de notre projet afin de pouvoir l'étendre et de configurer les particularités de nos environnements temporaires (utilisation de bases mémoire plutôt que fichier par exemple).
- values.yaml → contient les valeurs par défaut à utiliser au moment du déploiement de la Chart dans Kubernetes.
En plus de ces trois fichiers, Jenkins X génère un script Makefile à utiliser lors de la construction et du lancement de nos Charts.
2. Dockerfile
Le fichier Dockerfile est un fichier Dockerfile standard. Il permet à chaque projet de construire sa propre image Docker, avec ses spécificités, ou simplement en étendant une machine existante.
Par exemple, notre Dockerfile généré par Jenkins X est un Dockerfile Spring Boot standard étendant une image OpenJDK, exposant le port 8080 et lançant notre application au démarrage :
FROM openjdk:8 -jdk -slim
ENV PORT 8080
EXPOSE 8080
COPY build/libs/*.jar /opt/app.jar
WORKDIR /opt
CMD [ "java" , "-XX:+UnlockExperimentalVMOptions" , "-XX:+UseCGroupMemoryLimitForHeap" , "-jar" , "app.jar" ]
|
3. jenkins-x.yml
Depuis l'été 2019, Jenkins X fonctionne par défaut avec des pipelines serverless basées sur Tekton. Plus besoin désormais d'avoir un master Jenkins allumé en permanence, les machines de builds sont déployées automatiquement à la demande et les pipelines de construction et de déploiement sont automatiquement construites sur la base de notre fichier jenkins-x.yml.
Le fichier jenkins-x.yml suit une syntaxe propre à Jenkins X, ajoutant ainsi la seule dépendance forte à l'écosystème Jenkins X que j'ai pu remarquer. Peut-être qu'un jour, une solution plus universelle de définition de pipelines Tekton sera utilisée ?
La plupart du temps, ce fichier restera simple entre vos différents projets via l'utilisation de "buildpacks" qui décrivent les étapes de construction et de déploiement propres à ce buildpack.
Dans notre projet par exemple, lors de la génération, Jenkins X a créé un descriptif de pipeline très simple qui ne fait qu'étendre le buildpack gradle :
buildPack: gradle
|
4. OWNERS & OWNERS_ALIASES
Ces fichiers contiennent la liste des personnes pouvant approuver les Pull Requests (PR). Ils sont utilisés par Prow pour savoir si il est justifié de déclencher de nouvelles pipelines de construction au moment de l'ajout d'un commentaire sur une PR selon les procédures de ChatOps définies.
NB : Il existe deux types de projets dans Jenkins X : les projets dits 'classiques' qui ne demandent pas de déploiement, et les projets dits 'Kubernetes' qui eux nécessitent de passer par des phases transitoires supplémentaires de déploiement.
Créer vos modèles de projets
Dans notre premier article, nous avions vu comment créer un nouveau projet selon les modèles proposés par Jenkins X, appelés 'quickstart'. Mais si on regarde de plus près les différents quickstarts existants, ceux-ci restent très simples et ne proposent par exemple pas de modèles avec une connexion à une base de données par défaut.
Afin de créer vos propres modèles d'application réutilisables dans votre usine logicielle, il vous faudra créer vos propres quickstarts.
Créer un quickstart
En soi, un quickstart n'est qu'un projet GitHub qui va être cloné et pour lequel certaines valeurs vont être remplacées.
Comme son but est de faciliter la création de projet, il est entendu qu'un quickstart doit représenter la structure voulue du projet ainsi que l'ensemble des fichiers qui pourront être réutilisés par l'ensemble des applications.
Pour un projet maven/ Spring Boot, on parle par exemple ici des fichiers pom.xml, des fichiers de configuration spring, de la classe de lancement de l'application, des classes de configuration, etc.
Pour notre modèle d'application Spring Boot multi-modules, notre quickstart ressemble par exemple à ceci :
Comme vous pouvez le voir, on va utiliser le placeholder REPLACE_ME_APP_NAME pour représenter le nom de l'application qui sera ensuite générée à l'aide de ce quickstart.
Il n'existe pour le moment que peu de placeholders, dont voici la liste :
- REPLACE_ME_APP_NAME : pour remplacer par le nom de l'application
- REPLACE_ME_GIT_PROVIDER : pour remplacer par le type d'hébergement git (github, gitlab, etc...)
- REPLACE_ME_ORG : pour remplacer par le nom du compte hébergeant le projet Git
- REPLACE_ME_DOCKER_REGISTRY_ORG : pour remplacer par le nom du compte hébergeant les images docker
Vous pouvez également observer la présence du fichier jenkins-x.yml. Comme mentionné précédemment, ce fichier permet de décrire la pipeline à utiliser ou de la surcharger.
Ici, nous avons juste mentionné que dans le cadre de nos projets multi-modules nous utiliseront un build pack maison :
buildPack: factory-maven-java11
|
Créer un build pack
Un build pack est un ensemble de fichiers permettant de décrire une manière de compiler et de déployer un type d'application. On y retrouve donc a minima un fichier jenkins-x.yml décrivant la pipeline de compilation et de déploiement, mais également les fichiers templates Helm permettant le déploiement de nos Pods dans Kubernetes et les fichiers permettant la création de nos images Docker :
Dans le cadre de notre usine logicielle, nous avons par exemple fait en sorte que chacun de nos projets Spring soit connectés automatiquement à une application Spring Boot Admin afin de faciliter le monitoring des applications Spring.
Pour cela, nous rajoutons des templates permettant la création automatique de comptes de service (via les fichiers role.yaml, role-bindings.yaml et serviceaccount.yaml) qui permettront aux applications d'effectuer une découverte automatique du serveur Spring Boot Admin, ainsi que la mise à disposition des identifiants sécurisant la communication dans les variables d'environnements des containers docker déployés.
Du côté du fichier jenkins-x.yml et de la définition de notre pipeline, nous avons par contre juste étendu le build pack maven-java11 qui nous convenait très bien :
extends:
file: ../maven-java11/pipeline.yaml
# Un bug nous oblige a spécifier manuellement l'agent à utiliser
agent:
label: jenkins-maven-java11
container: maven-java11
|
Utiliser les quickstarts et build packs
Maintenant que nous avons créé notre quickstart et notre build pack, il ne nous reste plus qu'à les intégrer à notre installation Jenkins X pour pouvoir les utiliser.
Comme notre quickstart dépend de notre build pack, commençons par intégrer ce dernier :
Intégrer un buildpack dans une installation Jenkins X
Pour pouvoir utiliser un buildpack, il faut référencer le dépôt Git dans lequel il se trouve.
Comme à l'heure actuelle Jenkins X ne permet pas le référencement de plusieurs dépôts de build packs, nous avons fait le choix de fork le dépôt par défaut de Jenkins X et d'y ajouter ensuite notre nouveau build pack.
Nous exécutons ensuite la commande suivante pour définir le build pack à utiliser pour notre installation :
jx edit buildpack \\
-u <https: //github .com /esensconsulting/jenkins-x-kubernetes > \\
-r master
|
Maintenant que nous avons défini notre référentiel de buildpack, nous pouvons utiliser notre quickstart.
Intégrer un quickstart dans une installation Jenkins X
Pour intégrer notre quickstart, il nous suffit d'utiliser la commande suivante qui permettra à Jenkins X d'utiliser l'ensemble des projets de notre dépôt esensconsulting dont le nom démarre par "quickstart-":
jx create quickstartlocation \\
--url [<https: //g >](<https: //mygit .server.com/>)ithub.com \\
--owner esensconsulting \\
--includes quickstart-*
|
Utiliser notre quickstart et notre build pack
Maintenant que nous avons mis à disposition de notre installation Jenkins X notre quickstart et notre build pack, il est temps pour nous de les utiliser. Comme dans notre article précédent, il nous suffit de faire appel à la méthode :
jx create quickstart
|
Une fois le projet déployé, nous pouvons vérifier sur notre application Spring Boot Admin que l'application est bien disponible :
Le mot de la fin
Dans cet article, nous avons pu voir comment se décomposait un projet dans Jenkins X et comment il était possible de créer des modèles de projet pour lesquels les pipelines de déploiement et les dépendances sur des ressources externes pouvaient être définies de manière générique.
Mais il reste encore beaucoup de fonctionnalités de Jenkins X à voir, notamment autour des méthodologies de déploiement que Jenkins X peut fournir : Canary, Blue/Green, etc...
Nous ne manqueront pas de les aborder dans de futurs articles, stay tuned ! ;)
------------------------------
Article rédigé par Emmanuel, Tech Lead chez ESENS | Retrouvez tous nos articles sur le Blog ESENS
Vous êtes à la recherche d'un nouveau challenge ? Rejoignez l'équipe ESENS en postulant à nos offres d'emploi !