>
Cliquez sur l'image pour l'agrandir.
Jenkins fait partie des applicatifs fondateurs du CI/CD. Certains le considèrent d’ailleurs comme un dinosaure sur le marché du DevOps, prônant son remplacement par des outils plus modernes et plus optimisés.
Pourtant, Jenkins continue d’être très largement adopté et utilisé. Sa force réside justement dans son ancienneté. Au fil des années, il s’est enrichi de très nombreux plugins, lui permettant une intégration dans de nombreux écosystèmes.
Des générations d’administrateurs ont pu se former et monter en compétence sur le produit, permettant d’avoir aujourd’hui une grande communauté d’experts.
L’objectif de ce tutoriel est de faire une introduction à l’installation de Jenkins sous Kubernetes. Je n’ai pas vocation à détailler l’usage de Jenkins. Je n’ai pas le niveau suffisant pour ça, et Jenkins est tellement puissant en termes de faisabilité qu’il existe énormément de manières de faire et d’usages possibles.
Je souhaite simplement proposer quelques pistes pour déployer Jenkins sous K8S, avec comme objectif final d’inscrire cet article dans une série de tutoriels visant à illustrer un cas d’utilisation complet de CI/CD.
Contrairement à ArgoCD que j’ai pu présenter ici, focalisé sur le déploiement continu (CD) via une logique GitOPS, Jenkins peut être utilisé à la fois pour le CI (Intégration Continu) et du CD.
D’ailleurs, j’en profite pour faire un rappel sur cette distinction trop souvent oublié entre:
L’objectif ultime est de construire la fameuse chaine CI/CD, induisant une automatisation complète et continue de la création du code jusqu’à la livraison de l’application associée… toujours jusqu’en production !
Le marketing a souvent tendance à tout mélanger. Il n’est pas rare d’avoir, pour une application, que du CI ou que du CD, voir une automatisation en environnement de DEV uniquement… Sans jamais aller réellement jusqu’à l’industrialisation complète.
Certains outils sont d’ailleurs parfois orientés uniquement CI, ou CD. Jenkins fut d’abord pensé comme un outil de CI. Grâce à son extensibilité via des plugins, il s’est ensuite étendu au CD, ce qui en fait aujourd’hui une plateforme capable de gérer toute une chaîne de CI/CD.
Le revers de la médaille, c’est que Jenkins peut parfois faire les choses d’une manière plus complexe et/ou moins performante pour traiter un pan spécifique de la chaine CI/CD que des outils spécialisés.
Enfin, pour la petite histoire, Jenkins est dérivé d’Hudson, un logiciel développé par Kohsuke Kawaguchi, ingénieur chez Sun Microsystems en 2004. Suite au rachat de Sun par Oracle en 2010, des tensions sont apparues autour de Hudson provoquant une scission de la communauté en janvier 2011 menant à la création de Jenkins.
Depuis, Hudson est abandonnée… Jenkins est toujours là !.
Jenkins est aujourd’hui un projet maintenu par La Jenkins community, sous l’égide de la Jenkins project, hébergée par la CD Foundation (Continuous Delivery Foundation).
La CDF est à la CI/CD ce que la CNCF est au cloud-native.
Elle structure l’écosystème DevOps open source, en promouvant des projets clés comme Jenkins et Tekton, et en rassemblant une communauté mondiale autour de la livraison logicielle.
Avant de démarrer, il convient de faire le point sur Jenkins X. Bien qu’avec un nom très proche, Jenkin X est différent de Jenkins.
Cliquez sur l'image pour l'agrandir.
Jenkins X date de 2018 et n’a pas la même philosophie que Jenkins. Il a comme fondamental le souhait d’être un outil d’automatisation CI/CD natif pour Kubernetes en exploitant des pipelines prêts à l’emploi basé sur Tekton. Tekton est un framework open source de pipelines conçu pour k8s.
Voici un tableau comparant les deux produits:
Caractéristique | Jenkins | Jenkins X |
---|---|---|
Architecture | Monolithique extensible | Basé sur Kubernetes et Tekton |
CI/CD | CI centré, CD en plugin | CI/CD complet avec GitOps intégré |
Déploiement | VM, Docker, etc. | Kubernetes natif |
Pipelines | Jenkinsfile (Groovy) | YAML + Tekton |
Utilisation | Généraliste | Cloud-native, microservices, GitOps |
Dans les faits, l’adoption de Jenkins X est plutôt modeste. Il a souvent été préféré de conserver Jenkins et de l’étendre avec d’autres outils plus nativement compatibles avec Kubernetes, comme ArgoCD, pour traiter certaines parties de la chaine.
Le projet Jenkins X est beaucoup moins actif aujourd’hui. C’est pourquoi je préfère me tourner vers Jenkins et « l’adapter » pour le rendre exploitable sur K8S… d’ailleurs la communauté propose déjà beaucoup de choses pour cela, comme nous allons le voir.
Jenkins fonctionne sur le principe de contrôleur et d’agents. Le contrôleur servant de centre d'administration et de point d’entrée pour les configurations, les agents servant à exécuter les jobs contenus dans les pipelines. Je ne vais pas rentrer dans le détail, considérant que vous êtes déjà familier avec l’outil.
Disposant d’une autorité de certification interne (Certificate Authority (CA)) sous la forme de la solution Microsoft, j’exploite des certificats validés uniquement en interne de mon lab.
Jenkins devant être amené à communiquer avec d’autres composants de mon réseau, il se doit de reconnaitre cette CA. C’est d’ailleurs un cas courant en entreprise.
À la base, les images containers de Jenkins ne reconnaissent que les CA publics. Si je n’anticipe par ce point, j’aurais des erreurs dès lors que le contrôleur ou les agents chercheront à communiquer en SSL avec d’autres outils présents dans mon lab.
Il est très courant d’avoir à personnaliser les images de base de Jenkins. L’ajout du support de CA custom est une cause possible, mais d’autres besoins peuvent apparaître. Par exemple, dans mon cas, l’ajout du binaire kubectl pour les agents.
D’autres manières de faire sont possibles, mais c’est le choix que j’ai fait et que vous pourriez retrouver dans certaines structures.
On va donc commencer par construire l’image du contrôleur Jenkins.
Voici le dokerfile Dockerfile.server utilisé:
FROM jenkins/jenkins:2.492.2-lts
USER root
# Copie du CA
COPY ca-coolcorp.crt /usr/local/share/ca-certificates/ca-coolcorp.crt
# Ajout du CA au système et au keystore Java
RUN apt-get update && apt-get install -y ca-certificates openjdk-17-jre-headless \
#partie systeme
&& update-ca-certificates \
#partie keystore
&& keytool -importcert -noprompt \
-trustcacerts \
-alias my-ca \
-file /usr/local/share/ca-certificates/ca-coolcorp.crt \
-keystore "$JAVA_HOME/lib/security/cacerts" \
-storepass changeit
USER jenkins
À l’heure de la rédaction de l’article, je suis parti sur une base 2.492.2-lts.
Les modifications opérées vont être le rajout du certificat public de ma CA (ca-coolcorp.crt ), à la fois au sous-système Linux du conteneur (Debian), et au keystore de Jenkins.
En effet, Jenkins est développé en Java. Il n’utilise pas forcément la reconnaissance des certificats de confiance de l’OS sous-jacent. Il faut donc ajouter le CA dans un keystore java.
Il ne reste plus qu’à compiler l’image et à l’envoyer vers ma registry (gitlab).
docker build -t registry.gitlab.com/apps.coolcorp.priv/jenkins-custom:2.492.2-lts-v1 -f Dockerfile.server .
docker push registry.gitlab.com/apps.coolcorp.priv/jenkins-custom:2.492.2-lts-v1
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
On peut maintenant passer à l’agent, via le docker file Dockerfile.agent:
FROM jenkins/inbound-agent:3301.v4363ddcca_4e7-2
USER root
# Copie du CA
COPY ca-coolcorp.crt /usr/local/share/ca-certificates/ca-coolcorp.crt
# Ajout du CA au système et au keystore Java
RUN apt-get update && apt-get install -y ca-certificates openjdk-17-jre-headless \
#partie systeme
&& update-ca-certificates \
#partie keystore
&& keytool -importcert -noprompt \
-trustcacerts \
-alias my-ca \
-file /usr/local/share/ca-certificates/ca-coolcorp.crt \
-keystore "$JAVA_HOME/lib/security/cacerts" \
-storepass changeit
#ajout du binaire kubectl
RUN curl -LO "https://dl.k8s.io/release/v1.32.0/bin/linux/amd64/kubectl" && \
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl && \
rm kubectl
USER jenkins
Le principe est le même que pour le serveur, on n’y ajoute une étape supplémentaire via l’ajout du binaire kubectl (ici dans la version 1.32).
C’est effectivement l’agent qui sera chargé de passer des commandes kubectl, il faut donc lui intégrer le binaire. D’autres approches sont possibles. Celle-ci présente l’inconvénient de nécessiter de nouvelles images à chaque nouvelle version de kubectl, et d’avoir une dépendance entre l’agent utilisé et la version du cluster sur lequel il opère, mais elle reste simple et rapide à mettre en œuvre.
On compile l’image et on l’envoie dans la registry:
docker build -t registry.gitlab.com/apps.coolcorp.priv/jenkins-custom:agent-2.492.2-lts-v1 -f Dockerfile.agent .
docker push registry.gitlab.com/apps.coolcorp.priv/jenkins-custom:agent-2.492.2-lts-v1
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
On dispose maintenant de deux images « personnalisées ». Il n’est pas rare que d’autres ajustements soient à réaliser en entreprise. Ce n’est pas forcément bloquant, même pour un déploiement assisté de Jenkins via Helm, comme nous allons le voir par la suite.
Afin d’exécuter Jenkins, on va préférer lui dédier un namespace. Celui-ci respecte ma nomenclature, et peut se créer très facilement via la commande:
kubectl create ns prd-jenkins-lan
Cliquez sur l'image pour l'agrandir.
Comme à mon habitude et pour chaque déploiement d’une application sous Kubernetes, voici un schéma cible qui résume les objets qu’il va falloir manipuler:
Cliquez sur l'image pour l'agrandir.
Avant d’entamer le déploiement de Jenkins, on va gérer le besoin de stockage persistent. Comme j’ai opté pour helm pour installer Jenkins, je pourrais m’appuyer sur ce dernier pour provisionner le stockage dynamiquement. Mais c’est une chose que je préfère gérer en amont, pour une meilleure maitrise.
Jenkins peut se contenter d’un simple partage Network File System (NFS) pour héberger ses données et sa configuration. C’est d’ailleurs pour moi une grande force du produit: simple à sauvegarder, simple à restaurer...Vous représenter le volume NFS et Jenkins retrouve automatiquement ses petits.
Dans mon cas, je vais simplement provisionner un dossier sur mon NAS prévu pour être accessible à mon cluster Kubernetes.
Cliquez sur l'image pour l'agrandir.
On peut ensuite générer un PersistentVolume (pv) basé sur le CSI (Container Storage Interface) NFS. Pour ceux qui ne seraient pas familiers avec le principe de stockage sous k8S, je vous invite à lire cet article issu de mon cookbook K8S ainsi que cet article sur le déploiement du CSI NFS.
Voici le contenu du fichier 01-pv-jenkins-default.yml:
---
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/provisioned-by: nfs.csi.k8s.io
name: pv-jenkins-default
labels:
environment: prd
network: lan
application: jenkins
tier: default
spec:
capacity:
storage: 30Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
csi:
driver: nfs.csi.k8s.io
volumeHandle: /Volume1/nfsshare/rubikub.coolcorp.priv/namespaces/prd-jenkins-lan/default
volumeAttributes:
server: 192.168.10.152
share: /Volume1/nfsshare/rubikub.coolcorp.priv/namespaces/prd-jenkins-lan/default
Rien de nouveau sous le soleil, je fais pointer le volume directement sur mon export NFS /Volume1/nfsshare/rubikub.coolcorp.priv/namespaces/prd-jenkins-lan/default.
Voici le contenu du PersistentVolumeClaim associé à travers le fichier 02-pvc-jenkins-default.yml:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-jenkins-default
namespace: prd-jenkins-lan
labels:
environment: prd
network: lan
application: jenkins
tier: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 30Gi
volumeName: pv-jenkins-default
storageClassName: ""
Le pvc fait référence explicitement au pv sans passer par une StorageClass (sc).
Je place les deux dans un dossier storage et je peux les appliquer directement via la commande:
kubectl apply -f storage/
Cliquez sur l'image pour l'agrandir.
On peut contrôler l’état du pvc:
kubectl get pvc -n prd-jenkins-lan
Cliquez sur l'image pour l'agrandir.
Pour l’instant il n’est pas encore monté, puisqu’aucune application ne le sollicite.
Je pars du principe que vous avez les bases sur Helm et Kubernetes, si ce n’est pas le cas, n’hésitez pas à parcourir toutes les étapes de mon cookbook sur K8S. On va cependant faire un petit rappel rapide sur Helm
Helm est un gestionnaire de paquets pour Kubernetes simplifiant le déploiement d'applications. Il évite d'avoir à manipuler tous les yamls qui pourraient y être rattachés et préconfigure l'application pour un usage rapide.
Helm se présente sous la forme d'un simple binaire à déployer sur son cluster ou sur son environnement de travail destiné à piloter Kubernetes (où se trouve les élements d'accès (fichier config) au cluster).
Un paquet Helm est référencé sour le terme de Chart. C'est en réalité un dossier qui va contenir tout les manifests nécessaires à l'application ainsi qu'un fichier values.yaml contenant la configuration de l'application et les variables à passer aux différents objets Kubernetes.
Dans un usage par défault, tout cela est "masqué" à l'utilisateur qui peut se contenter de lancer l'installation de l'application souhaité avec une simple commande Helm. Ces charts sont disponibles dans des repos, à l'image de ce que l'on peut trouver sur les distributions Linux..
On démarre donc par l'ajout des ces repos .
helm repo add jenkins https://charts.jenkins.io
helm repo update
Cliquez sur l'image pour l'agrandir.
Si j’apprécie beaucoup Helm, il me frustre également. Initialement, si on se contente de déployer les applications packagées, on ne sait pas comment elles seront configurées ni quels objets seront déclarés et avec quelle configuration.
Il est donc conseillé de toujours jeter un œil sur les « values » par défaut. Elles peuvent être directement accessibles sur le github associé repo du projet ou peuvent être extraites avec la commande helm show values nom_repo
Personnellement j’ai pris l’habitude d’exporter ces valeurs dans un fichier default-value.yml au sein d’un sous-dossier helm:
helm show values Jenkins/jenkins > helm/default-value.yml
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
Je peux ainsi m’inspirer de la configuration proposée pour construire mon propre fichier custom-values.yml.
Voici d’ailleurs son contenu:
controller:
namespaceOverride: prd-jenkins-lan
#Utilisation de l'image custom
imagePullSecretName: sec-jenkins-registry
image:
registry: registry.gitlab.com
repository: apps.coolcorp.priv/jenkins-custom
tag: 2.492.2-lts-v1
pullPolicy: Always
#Précision sur l'URL de jenkins
jenkinsUrlProtocol: https
jenkinsUrl: https://jenkins.coolcorp.priv
#On ne créé par un ingress automatiquement
ingress:
enabled: false
service:
type: ClusterIP
port: 8080
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2000m"
memory: "4Gi"
#Récupération du pvc existent
persistence:
enabled: true
existingClaim: pvc-jenkins-default
#Configuration de l'agent
agent:
enabled: true
#Usage d'un compte de service dédié
useDefaultServiceAccount: false
serviceAccount: sa-jenkins-agent
#url du controleur
jenkinsUrl: https://jenkins.coolcorp.priv
#image de l'agent à utiliser
imagePullSecretName: sec-jenkins-registry
image:
repository: registry.gitlab.com/apps.coolcorp.priv/jenkins-custom
tag: agent-2.492.2-lts-v2
Comme vous pouvez le constater, il est nettement plus petit, car je n’y fais figurer que les options que je souhaite modifier.
Globalement, je vais préciser les images à utiliser. J’indique celles que j’ai « customisé » en début d’article.
Je viens ajouter également la référence à l’url ou sera accessible le contrôleur (jenkins.coolcorp.priv).
Bien sûr, je déclare le pvc récemment créé,pvc-jenkins-default afin qu’on l’utilise sans que Helm n'ait a créer d'autres objets de stockage.
Point important également, au niveau de la section agent, je précise un compte de service à utiliser: sa-jenkins-agent. Ce passage sera détaillé dans une partie dédiée, mais il faut bien comprendre que l’agent va devoir opérer des actions sur le cluster. Il faut donc qu’il le fasse sous l’identité d’un compte autorisé à manipuler les objets sur le cluster.
Enfin, comme on le verra ensuite, je ne souhaite pas que soit créer automatiquement un objet de type ingress. On s’en chargera nous-mêmes.
Avant de lancer l’installation, il y a un prérequis. Étant donné que j’utilise des images personnalisées issues d’une registry privée, il me faut créer le secret contenant le token d’accès à cette registry.
Ce secret, que je vais nommer sec-jenkins-registry, est d’ailleurs renseigné dans le fichier custom-values.yml dans le champs imagePullSecretName.
Voici le contenu du fichier 01-sec-jenkins-registry.yml (avec de fausse valeur bien sûr… 😊):
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5naXRsYWIuY29tIjp7
kind: Secret
metadata:
name: sec-jenkins-registry
namespace: prd-jenkins-lan
type: kubernetes.io/dockerconfigjson
On l’applique dans la foulée:
Kubectl apply -f 01-sec-jenkins-registry.yml
Cliquez sur l'image pour l'agrandir.
Le déploiement de Jenkins peut enfin se faire en précisant mon fichier de valeurs personnalisées:
helm install Jenkins Jenkins/jenkins -n prd-jenkins-lan -f helm/custom-values.yml
Cliquez sur l'image pour l'agrandir.
Notez bien la sortie de helm, qui précise d’utiliser cette instruction: kubectl exec -namespace prd-jenkins-lan—it svc/Jenkins -c Jenkins -- /bin/cat /run/secrets/additional/chart-admin-password && echo
pour obtenir le mot de passe du compte admin par défaut.
Récupérez-le et stockez-le en lieu sûr.
Cliquez sur l'image pour l'agrandir.
La finalisation de l’installation prend quelques minutes, on peut vérifier le succès de l’opération avec la commande:
kubectl get pod -n prd-jenkins-lan
Cliquez sur l'image pour l'agrandir.
(Pour ceux qui ne l'auraient pas remarqué, au vue du nom du pod, on se rend compte que Helm a déployé Jenkins sous forme de StatefulSets)
Notre pod Jenkins est bien là… Encore faut-il le rendre accessible.
C’est le moment de parler ingress. Pour rappel cet objet permet d’exposer son application à l’extérieur du cluster K8S. Si vous êtes un peu perdu, n’hésitez pas à parcourir cet article.
Mon instance de Jenkins sera publiée sur l’URL https://jenkins.coolcorp.priv. Soit un site HTTPS avec un certificat.
Il me faut donc créer ce certificat en amont et l’enregistrer dans un secret pour qu’il puisse être utilisé par l’ingress.
Il est possible d’automatiser totalement la création et le mappage du certificat, grâce à l’usage de Cert Manager. J’ai d’ailleurs un article dédié si le sujet vous intéresse.
Ici, je vais rester sur une méthode à l’ancienne. Je vais d’abord générer ma clef et ma demande de certificat associée (fichier csr).
openssl req -new -nodes -sha256 -keyout jenkins.coolcorp.priv.key -out jenkins.coolcorp.priv.csr -newkey rsa:4096 -subj "/C=FR/ST=Ile-de-France/L=Paris/O=COOLCORP/OU=Infrastructure/CN=jenkins.coolcorp.priv" -reqexts SAN -config <(printf "[req]\ndistinguished_name = req_distinguished_name\n[req_distinguished_name]\n[SAN]\nsubjectAltName=DNS:jenkins.coolcorp.priv")>
Cliquez sur l'image pour l'agrandir.
Ensuite, je soumets mon CSR à mon autorité de certification (ici sous Windows): certreq -attrib "CertificateTemplate:TPL-SRV-WEB-DEFAULT" -submit .\jenkins.coolcorp.priv.csr
Cliquez sur l'image pour l'agrandir.
Pour enfin récupérer mon certificat.
J’ai donc, en bout de course, un certificat et ma clef. Les deux vont me permettre de créer le secret sec-jenkins-cert.
kubectl create secret tls sec-jenkins-cert --cert=jenkins.coolcorp.priv.cer --key=jenkins.coolcorp.priv.key -n prd-jenkins-lan
Cliquez sur l'image pour l'agrandir.
Je ne rentre pas dans le détail, chacun a souvent sa propre mécanique de gestion des certificats en interne. Sachez que vous pouvez soit générer le secret en utilisant la clé et le certificat, soit déléguer cette tâche à l’outil Cert-Manager. Pour ceux qui comme moi ont une CA Windows, vous pouvez meme suivre ce tutoriel pour tirer partie de l'automatisation via le protocole ACME
On peut passer à l’ingress lui-même, détaillé dans ce fichier 02-ing-jenkins-default.yml:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-jenkins-default
namespace: prd-jenkins-lan
labels:
environment: prd
network: lan
application: jenkins
tier: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
ingressClassName: traefik-lan
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik-lan
tls:
- hosts:
- jenkins.coolcorp.priv
secretName: sec-jenkins-cert
rules:
- host: jenkins.coolcorp.priv
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
On y retrouve le secret contenant le certificat et la référence à l’ingress class « traefik-lan » a utiliser.
Là aussi, je ne donne pas davantage d’explication. L’usage de traefik vous est décrit ici.
Concernant le nom du service jenkins et le port 8080 vers lesquels rediriger la requête, il s'agit du service créer par helm directement. On peut le retrouver via la commande:
kubectl get service -n prd-jenkins-lan
On applique l’ingress:
kubectl apply -f 02-ing-jenkins-default.yml
Cliquez sur l'image pour l'agrandir.
On peut vérifier l’accès à l’interface de Jenkins via l’URL souhaitée (attention à bien avoir pris soin de faire son enregistrement DNS) et en utilisant le mot de passe du compte admin récupéré précédemment.
Cliquez sur l'image pour l'agrandir.
On dispose maintenant d’une instance Jenkins déployée sur le cluster Kubernetes.
Avant d’aller plus loin, on va revenir sur le compte de service sa-jenkins-agent utilisé par l’agent.
Celui-ci n’existe pour l’instant pas dans le cluster (on a spécifié dans le fichier value de helm qu’on ne souhaitait pas utiliser le compte de service par défaut.).
Il va falloir le créer via le fichier 01-sa-jenkins-agent.yml:
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-jenkins-agent
namespace: prd-jenkins-lan
On va dédier un rôle à ce compte. Cela va permettre de définir précisément ce que va pouvoir faire Jenkins sur ce cluster.
Ce rôle est défini dans 02-clusterrole-jenkins-agent.yml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: clusterrole-jenkins-agent
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "delete", "update", "patch"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
Pour le besoin de ce tutoriel, on est sur une base simple. On n’autorise que la manipulation des pods.
Il reste à faire l’association de ce rôle au compte via l’objet clusterrolebinding décrite dans le yaml 03-clusterrolebinding-jenkins-agent.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: clusterrolebinding-jenkins-agent
subjects:
- kind: ServiceAccount
name: sa-jenkins-agent
namespace: prd-jenkins-lan
roleRef:
kind: ClusterRole
name: clusterrole-jenkins-agent
apiGroup: rbac.authorization.k8s.io
Je place ces trois fichiers dans un dossier right, et je peux les appliquer en une opération:
kubectl apply -f right/
Cliquez sur l'image pour l'agrandir.
Si vous le souhaitez, vous pouvez parcourir cet article qui parle de la gestion des droits sous K8S et de la mécanique RBAC qui s’y rattache. Vous comprendrez ainsi mieux la logique de ces trois objets.
Tout étant maintenant prêt, il ne reste plus qu’à valider tout ça.
Pour cela on va utiliser une pipeline DEMO, très basique, ayant uniquement vocation à lister les pods du cluster.
Voici le contenu de la pipeline:
pipeline {
agent any
stages {
stage('Test Kubernetes Access') {
steps {
sh 'kubectl get pods -A'
}
}
}
}
Cliquez sur l'image pour l'agrandir.
Comme mentionné au début de l’article, le but de ce tutoriel n’est pas d’expliquer le fonctionnement de Jenkins, mais de le rendre apte à s’exécuter dans un cluster Kubernetes et à y orchestrer des tâches.
On peut lancer la pipeline.
On observe alors qu’un nouveau pod va être provisionné dans le namespace prd-jenkins-lan.
Cliquez sur l'image pour l'agrandir.
Ce pod représente l’agent piloté par le contrôleur. Il va charger l’image que nous avons détaillée dans le fichier value helm et construite au début de l’article.
Cette image contenant kubectl, l’instruction get pod déclarée dans la pipeline va pouvoir être jouée.
L’agent va exécuter la commande sous l’identité du compte de service sa-jenkins-agent qui dispose du rôle clusterrole-jenkins-agent l’autorisant à manipuler les pods.
On obtient donc bien en sortie la liste des pods du cluster.
Cliquez sur l'image pour l'agrandir.
Cliquez sur l'image pour l'agrandir.
A noter que le pod de l'agent est supprimé une fois la pipeline terminée
Veuillez noter qu’on n’a pas eu à indiquer sur quel cluster agir, Jenkins s’exécutant sur le cluster lui-même, il va utiliser ce dernier par défaut. Cette intégration est possible grâce à l’usage du plugin Kubernetes inclus et configuré de base lors de l’usage de helm.
Jenkins est désormais déployé sur le cluster et en mesure d’y réaliser des actions.
La pipeline DEMO n’a pas grand intérêt, mais elle démontre la faisabilité de la manipulation des objets du cluster par Jenkins, ceci de manière totalement interne.
Il devient donc possible de s’appuyer sur la modularité de Jenkins et de la puissance de ses pipelines pour imaginer des enchainements de taches mêlant à la fois des composants externes au cluster et le cluster lui-même. Par exemple, récupérer les sources sur un repo git et les compiler dans un pod dédié, exécuter des actions au sein des pods… A chacun de trouver ses uses cases ! Il ne reste plus qu’à faire jouer son imagination !