Introduction

Depuis plus de 10 ans, Jenkins est un outil majeur dans le monde du développement logiciel et de l’automatisation. Reconnu pour sa simplicité de mise en oeuvre et sa large palette de fonctionnalités, il a été mis en place au fil des ans dans environ 70% des sociétés ayant un besoin d’automatisation.

Avec l’avènement du mouvement DevOps, et même du GitOps, qui vise à automatiser le déploiement en production de chaque changement dans le code, les outils ont dû élargir leur champ d’action pour passer de l’intégration continue au déploiement continu. Ainsi, Jenkins a dû opérer un certain nombre de changements que je vous présente dans cet article.

Ces changements ont pris du temps. Jenkins doit encore combler son retard technologique pour être au niveau des nouveaux outils Pure player concurrents tels que Drone.io ou CircleCI.

Enfin, Jenkins a parfois une mauvaise réputation, principalement à cause de la gestion coûteuse des plugins et de la configuration fastidieuse des jobs. Ici aussi, cet article propose des solutions pour éviter ces désagréments et pour s’approcher d’une exploitation Cloud Native : entièrement pilotée par le code.

Avant d’aller plus loin, définissons les notions de CI et CD.

L’intégration continue (ou Continuous Integration) est une pratique permettant de valider que les nouvelles contributions sur la base de code “s’intègrent” bien avec le reste du code applicatif. Cette vérification peut prendre diverses formes : compilation, tests unitaires, etc. Si ce garde-fou qualitatif est validé, la modification pourra être mergée.

L’acronyme CD peut avoir deux significations :

  • La livraison continue (Continuous Delivery).
  • Ou le déploiement continu (Continuous Deployment).

Ces deux pratiques sont assez proches, et visent toutes deux à automatiser la mise à disposition de l’application. L’objectif est dans la continuité de l’intégration continue, en poussant plus loin le domaine de responsabilité et la maîtrise de qualité associée. La pratique du déploiement continu est généralement mise en oeuvre dans les organisations dites DevOps.

what-is-ci-cd
Source : https://www.redhat.com/fr/topics/devops/what-is-ci-cd

Un peu d’histoire

2005 – Naissance d’Hudson

Jenkins est vieux… Alors employé de Sun Microsystems, Kohsuke Kawaguchi a initié ce produit Java en 2004 pour une première release en février 2005. Nommée Hudson, cette application Web va rapidement détrôner les concurrents d moment : CruiseControl et Continuum jugés difficiles à mettre en oeuvre et à maintenir.

Au début des années 2010, le rachat de Sun par Oracle entraîne un fork et un rebranding de Hudson vers Jenkins.

À l’époque, le principal atout de cet ordonnanceur de tâches est l’ajout facile de fonctionnalités, via sa myriade de plugins pour le build (Ant, Maven, …) et le reporting qualité (JUnit, FindBugs, Cobertura, ...). Il devient logiquement la référence des outils d’intégration continue, accompagné sur ce marché de Bamboo (édité par Atlassian) et TeamCity (édité par JetBrains).

2016 – Jenkins 2.0

En 2016 émerge une volonté de modernisation. Après 10 ans de bons et loyaux services, Jenkins doit évoluer pour embrasser le mouvement grandissant de l’automatisation des déploiements. Les jobs Jenkins sont alors toujours construits via un empilement de plugins et de steps à configurer manuellement, via une interface graphique comprenant une foultitude de boutons.

Cette version 2.0 s’attache à fournir trois principales évolutions :

  • Une amélioration du mode de premier déploiement de l’outil.
  • Une interface graphique repensée, avec le projet Blue Ocean.
  • Les pipelines, décrits par le code.
Assistant premier démarrage
Assistant premier démarrage

Interface BlueOcean
Interface BlueOcean (Source : https://www.capterra.com/p/171026/Jenkins)

Pipeline as code

Définition

La notion de pipeline tire son origine d’un mode de communication des ressources d’un système, où la sortie d’un processus est consommé en entrée du processus suivant.

Le pipeline peut être défini comme :

  • Le garant de la qualité d’une brique logicielle, du code (build) à l’exploitation (run).
  • Une succession de tâches, portées par des outils souvent hétérogènes.
  • Un mécanisme qui assure que l’échec d’une étape empêchera l’exécution des étapes suivantes.

Son objectif et sa finalité seront différents selon les organisations et les besoins, allant d’une simple livraison d’artefact à la mise en production automatisée (CI / CD).

La pratique du pipeline-as-code vise à décrire dans le code source la succession et le déroulement des différentes étapes composant le pipeline du produit associé.

Jenkinsfile

Le fichier source de description du pipeline tel qu’attendu par Jenkins 2 s’appelle le Jenkinsfile. La convention de nommage est largement inspirée des outils du moment (Dockerfile, Puppetfile, ...).

D’abord initié au format Scripted pipeline, les contributeurs ont rapidement fourni une alternative avec le Declarative pipeline. Cette seconde forme est conseillée car elle offre une convention et un format plus clair et lisible (bien que plus verbeux). Toute la documentation est disponible sur la documentation Pipeline Syntax.

Exemple :

Scripted pipelineDeclarative pipeline
node('docker') {
  stage 'Gradle Analysis'
  sh './gradlew sonarqube'
}
pipeline {
  agent {
    label 'docker'
  }
  stages {
    stage('Gradle Analysis') {
      steps {
        sh './gradlew sonarqube'
      }
    }
  }
}

Apports

Utiliser un fichier source pour exécuter un pipeline apporte de nombreux avantages :

  1. Fin de “l’usine à clics”. Possibilité : ajout d’une étape sans utiliser la WebUI (peu UX-friendly…).
  2. Un build par branche. Possibilité : proposition d’une montée de version Maven via une Pull Request sur le Jenkinsfile. Le build de cette branche assurera la non régression.
  3. Le pipeline devient un livrable versionable avec l’ensemble du code source.
  4. Factorisation du code. Possibilité : réutilisation de fragments de code entre plusieurs pipelines, via l’extension Shared Library (ou même la Modular Pipeline Library).
  5. Tests unitaires. Possibilité : utilisation de la librairie Jenkins Pipeline Unit.

Quid des plugins ?

Pour aller plus loin et gommer un second inconvénient historique de Jenkins avec sa gestion fastidieuse de ses milliers de plugins, un outil vient à la rescousse : Docker. Chaque étape de votre pipeline ayant besoin d’un outil peut (et doit) utiliser une image Docker  pour lancer cet outil. Ainsi, plus besoin de plugin NPM et de ses N configurations pour avoir les N différentes versions dont vous avez besoin : chaque Jenkinsfile va spécifier l’image dont il a besoin (dans la version requise). Cerise sur le gâteau : les montées de version ne seront plus qu’une simple PR.

Deuxième effet KissCool® : vos tâches deviennent agnostiques vis-à-vis de l’agent où elles seront exécutées. À part Java, Git et Docker, il n’y a plus d’outils à pré-installer sur les workers avant d’y exécuter vos pipelines.

Les seuls plugins requis restent ceux visant à intégrer Jenkins dans votre écosystème :

  • Git + Intégration GitHub, Bitbucket ou GitLab.
  • Plugin SSH ou K8S selon le mode de provisioning de vos agents.
  • Intégration avec les API tierces (Slack, SSO, …).

Jenkins as code


Une fois que les pipelines sont dans le code, les seuls “clics” restants sont ceux pour la mise en oeuvre initiale et le paramétrage de l’instance Jenkins.

Pour passer d’un Jenkins géré en mode “animal de compagnie” au Jenkins devenu “bétail”, il reste à décrire dans le code les paramètres tels que l’URL, la configuration SMTP, SSO ou encore la gestion des agents.

Un projet vient répondre à ce besoin : Jenkins Configuration as Code (ou projet JCasC). Son principe est de décrire tous les points de paramétrage globaux au sein d’un seul fichier YAML. Un simple outil de gestion de configuration (Puppet, Ansible, …) couplé avec ce fichier permet d’instancier un Jenkins opérationnel par le code. Si vous disposez d’un cluster Kubernetes, Jenkins pourra également y être déployé sans effort et pré-configuré.

Exemple :

jenkins:
  systemMessage: "Jenkins configured automatically by JCasC"
  securityRealm:
    ldap:
      configurations:
        - groupMembershipStrategy:
            fromUserRecord:
              attributeName: "memberOf"
          inhibitInferRootDN: false
          rootDN: "dc=acme,dc=org"
          server: "ldaps://ldap.acme.org:1636"
  mailer:
    replyToAddress: do-not-reply@acme.org
    smtpHost: smtp.acme.org
    smtpPort: 4441


Dans cette description par le code, il conviendra également de préparer l’intégration avec l’outil SCM via le plugin approprié : GitLab, GitHub ou Bitbucket. Chacun de ces plugins fournit un scan de tous les dépôts de l’organisation, l’instanciation des jobs multi-branches et le positionnement d’un webhook pour la notification des push.

Ainsi, votre Jenkins sera non seulement pré-configuré, mais également déjà peuplé avec les jobs de vos différents projets.

Jenkins est-il Cloud Native ?

Jenkins est-il le meilleur candidat pour construire, tester et déployer une application dans le cloud (public ou hébergé) ?

Positionnement dans l'écosystème

La comparaison est difficile tant les critères sont différents selon les organisations. Dans cet article, deux critères ont principalement été évoqués :

  • Diversité des cas d’usages adressables.
  • Simplicité de première mise en oeuvre.


Le principal critère différenciant de Jenkins sur ces deux sujets est bien la diversité des cas d’usages qu’il peut adresser. Les efforts décrits plus haut dans cet article tendent à simplifier sa mise en oeuvre.

D’autres critères sont à prendre en compte lors du choix d’un outil : licence, support, … Pour compléter, voici les atouts et faiblesses que peut avoir Jenkins :

Atouts :

  1. Communauté et support
  2. Pas de vendor lock-in avec le gestionnaire de source (VS GitHub actions, GitLabCI)
  3. Licence MIT (gratuit)

Faiblesses :

  1. DSL spécifique des pipelines (même si un plugin pipeline-as-yaml est en cours de développement !).
  2. Historique Java pose parfois souci (syntaxe Groovy, erreurs CPS…).
  3. Pas de version SaaS gratuite.
  4. Coûts liés à l’infrastructure et à la maintenance.

Jenkins X

Impossible de terminer cet article sans évoquer Jenkins X, fruit d’une initiative de la communauté Jenkins pour construire un nouvel outil nativement conçu pour le cloud. Développé en Go, il s’exécute uniquement sur un cluster Kubernetes et est basé sur d’autres technologies de la CNCF : Tekton, Prow, … Par défaut, Jenkins X s’utilise via une CLI uniquement.

/!\ “Jenkins X est à Jenkins ce que Javascript est à Java” : ce ne sont pas les mêmes outils, ils sont construits sur une architecture et des technologies différentes, mais ils répondent à un besoin commun : automatiser des tâches.

Conclusion

Jenkins n’est peut-être pas l’outil qui sera le plus apte à réduire votre time-to-market pour un tout nouveau projet construit from scratch. Si vous avez un ou plusieurs produits, avec le même workflow, nul besoin de s’encombrer d’un outil adressant autant de cas d’usages. Jenkins pourrait répondre à ce besoin mais d’autres outils le feront plus rapidement, au choix : DroneIO, CircleCI ou Jenkins X par exemple.

En revanche, si votre organisation comporte une hétérogénéité de projets, produits et workflows, avec différentes intégrations à fournir, alors Jenkins aura toute sa place. Cet outil vous permettra d’adresser tous les besoins, peu importe leurs disparités : lancement récurrent, sur événement ou manuel, interface de lancement de tâches avec saisie (par des profils peu ou pas techniques), GitOps on Kubernetes, décoration de PR sur GitHub…

L’important à retenir pour assurer une maintenabilité optimale et un effort d’exploitation minimal : tout décrire dans le code, via des pipelines utilisant uniquement Docker !


Sources :