Comment nous avons migré plus de 350 jobs Maven en Pipeline as code avec Jenkins 2 et Docker !

Part1: Créer ses propres images Docker pour Jenkins

 

Il y a un an, chez eXo, nous avons pris la décision de construire tous nos projets dans des conteneurs Docker.

Dans cette série d’articles, nous vous expliquerons pourquoi et comment nous avons migré plus de 350 jobs Maven « standards » de Jenkins vers du Pipeline as code sur nos serveurs d’Intégration Continue avec Jenkins 2 et Docker.

C’est l’occasion de revenir sur les problèmes que nous avons rencontrés ainsi que les solutions apportées, et sur certaines bonnes pratiques autour des builds Maven / Gradle / Android dans des conteneurs Docker, le tout géré par du Pipeline as Code de Jenkins.

Comme toute migration technique importante, nous l’avons réalisée étape par étape. Les 3 grandes étapes ont été les suivantes:

  • Créer nos propres images CI Docker
  • Utiliser les plugins Jenkins Pipeline & Pipeline Docker
  • Générer tous les jobs Pipeline avec le Job DSL plugin

Le diagramme suivant représente le flux de travail lorsque toutes ces étapes sont effectuées:

Diagramme flux de travail avec étapes effectuéesDans cet article, nous détaillerons le contexte (pourquoi nous l’avons fait) et la première étape de cette migration sur la création de vos propres images CI Docker.

Qu’avions-nous à construire ?

eXo Platform est bâtie sur l’open-source et les standards ouverts. La plateforme est compatible avec la pile Java EE et s’appuie sur de nombreuses bibliothèques et composants open-source.

Mobile 1Mobile 2Desktop

Pour différentes raisons que nous allons vous expliquer, nous avons à gérer un grand nombre de builds sur nos serveurs d’Intégration Continue .

Composants d’eXo Platform et Add-ons

La première raison est que nous avons des dépôts git pour chacun des composants requis dans les livrables des distributions d’eXo Platform:

  • 25+ composants à construire
    • projets pour la plateforme (cf. diagramme ci-dessous)
    • projets Juzu…
  • De nombreux Add-ons
    • 15+ Add-ons supportés
    • 100+ Add-ons communautaires
  • Projets natifs pour le mobile
    • application Android
    • application iOS

Composants d’eXo Platform et Add-onsGit Workflow

Nous utilisons un workflow git basé sur un modèle de branches que tous les projets eXo doivent suivre:

  • develop : branche qui contient les derniers développements validés
  • feature/xxx : branches dédiées aux nouvelles fonctionnalités majeures (de nombreux commits), « xxx » correspond au nom de la fonctionnalité.
  • stable/xxx : branches utilisées pour faire des releases et pour corriger des problèmes sur des versions stables. « xxx » correspond au numéro de version stabilisée (e.g 1.0.x).
  • fix/xxx : branches dédiées aux correctifs qui doivent être ensuite intégrés dans la branche develop. Dans certains cas, ces corrections peuvent être aussi appliquées sur la branche stable.
  • integration/xxx : branches dédiées aux processus automatiques (exemple: processus de traductions…).
  • poc/xxx : branches dédiées à la réalisation de Proof of Concept (PoC)

Workflow git, modèle de branches pour suivre les projets eXoClients et versions d’eXo Platform

Depuis près de 15 ans maintenant, eXo a publié de nombreuses versions d’eXo Platform. Avec eXo Platform 5 en cours de développement et les versions que nous devons maintenir pour nos clients (eXo Platform 4.x: 4.0, 4.1, 4.2, 4.3, 4.4), nous avons ainsi plusieurs versions de nos environnements de build à gérer.
Actuellement, nous devons être en mesure de construire des projets avec les versions JDK6, JDK7 ou JDK8 et Maven 3.0, Maven 3.2 ou Maven 3.3. L’application Android native est construite par Gradle.

Vous vous souvenez comment créer un job Maven dans l’interface Jenkins ?

Même si Jenkins 2 a fait de nombreux efforts pour l’améliorer, il est toujours contraignant de créer de nouveaux jobs Maven via l’interface utilisateur, comme vous pouvez le voir ci-dessous:

comment créer un job Maven dans l’interface Jenkins

“Jenkins DSL et jobs Pipeline dans Docker à la rescousse !”

Pour ces différentes raisons, nous devions gérer beaucoup de jobs Maven à partir de l’interface utilisateur de Jenkins et maintenir nombre d’outils dans plusieurs versions (Maven, JDK …) sur les agents Jenkins ainsi que sur les postes de développeurs. Ce travail n’étant ni intéressant ni efficace, nous avons décidé de trouver une solution pour l’automatiser et le gérer différemment.

La technologie basée sur les conteneurs (Docker), combinée  à l’émergence d’outils d’automatisation dans Jenkins avec Pipeline et l’efficacité du DSL Job plugin, nous a alors semblé être la meilleure solution dans le contexte eXo.

1ere étape: Créer ses propres images Docker

Il est important de respecter les bonnes pratiques générales lorsque l’on créé nos propres images Docker, mais également quelques spécificités propres aux environnements de build.

Création de nos propres images DockerChoisir une image de base pour la distribution

Tous nos serveurs qui font office d’agents Jenkins sont gérés à partir de Puppet et sont basés sur la distribution Ubuntu. Nous avons donc décidé d’utiliser une image Docker plus légère basée sur cette distribution nommée baseimage-docker.

C’était un bon compromis entre une image très légère comme Alpine qui avait des problèmes liés à l’installation de JDK et l’image Docker officielle d’Ubuntu trop volumineuse.

FROM  phusion/baseimage:0.9.21
LABEL MAINTAINER « eXo Platform <docker@exoplatform.com> »

Définir la locale

Qui n’a jamais eu de tests en échec en raison de problèmes d’encodage ? Les tests passent  sur mon poste Linux, mais ils échouent sur le portable de mon collègue sous Windows !

Il est très fortement recommandé de définir une locale pour s’assurer que tous les développeurs auront le même comportement quel que soit leur environnement et que ce comportement sera conforme à la configuration du serveur d’Intégration Continue.

Créer un utilisateur CI dédié

“…take care of running your processes inside the containers as non-privileged users (i.e., non-root).” est l’une des recommandations les plus importantes du guide de sécurité Docker.

Dans le contexte de Jenkins, il est important de créer un utilisateur de CI dédié qui correspond à l’uid:gid de l’utilisateur utilisé par Jenkins sur vos agents.

En effet, lorsque Jenkins exécute un job Pipeline avec Docker, il partage l’espace de travail du job ainsi que d’autres dossiers requis dans le conteneur Docker.

Par exemple, Jenkins exécute la commande suivante sur l’agent:

La création d’un utilisateur CI dédié vous évite ainsi les problèmes d’autorisations avec les volumes Docker.

Vous pouvez constater que nous définissons la variable EXO_CI_USER_UID avec l’instruction Docker ARG, elle aura son importance pour aider le développeur dans son environnement de de développement local et nous expliquerons pourquoi plus loin dans cette série d’articles.

ENTRYPOINT et CMD

Dans un Dockerfile, l’instruction ENTRYPOINT est une définition facultative pour la première partie de la commande à exécuter. Ainsi, les instructions ENTRYPOINT ou CMD, spécifiées dans votre Dockerfile, identifient l’exécutable par défaut pour l’image Docker. Mais la meilleure solution est de combiner ces deux instructions en utilisant CMD pour fournir des arguments par défaut pour le ENTRYPOINT.

Dans les versions antérieures du plugin Jenkins Docker Pipeline, Jenkins n’utilisait pas l’option –entrypoint lors du démarrage des conteneurs, la commande exécutée était alors:

 

Dans ce cas, si votre image Docker utilisait l’instruction ENTRYPOINT pour déclarer une commande à exécuter, Jenkins ne pouvait pas utiliser votre image.

C’est pourquoi nous avons ajouté un script personnalisé dans nos images Docker, comme solution de contournement, afin de pouvoir exécuter Maven comme commande au démarrage du conteneur, mais également la commande cat et d’autres commandes à partir du moment où elles sont appelées via un chemin absolu:

Dockerfile

docker-entrypoint.sh

Depuis plusieurs versions du plugin Jenkins Docker Pipeline, ce problème a été corrigé pour utiliser l’option –entrypoint afin que l’instruction ENTRYPOINT soit toujours surchargée:

Utiliser l’héritage pour éviter la duplication de code

Nous avons créé et continuons à créer des images Docker pour couvrir toutes nos environnements de build, aujourd’hui cette liste contient notamment :

  • exoplatform/ci:jdk6-maven30
  • exoplatform/ci:jdk7-maven30
  • exoplatform/ci:jdk7-maven32
  • exoplatform/ci:jdk8-maven32
  • exoplatform/ci:jdk8-maven33
  • exoplatform/ci:jdk8-gradle2

Comme vous pouvez l’imaginer, il n’y a pas beaucoup de différences entre toutes ces images. Nous avons donc créé des images de base CI à plusieurs niveaux afin d’éviter autant que possible la duplication du code.

Le schéma ci-dessous montre comment ces images sont organisées :

Image de base CI sur docker avec héritage pour éviter la duplication de codeCi-dessous, il s’agit d’un extrait du Dockerfile pour l’image exoplatform/ci:jdk8-maven33 et vous pouvez voir qu’il n’y a que des instructions Docker liées à l’installation Maven car toutes les autres configurations ont été effectuées dans les images héritées (définir les paramètres régionaux, créer un utilisateur CI …).

Comme expliqué précédemment dans cet article, nous avons combiné les instructions Docker ENTRYPOINT et CMD pour pouvoir exécuter toutes les commandes Maven dans ce conteneur facilement:

Et nous ajoutons également un script personnalisé, pour pouvoir exécuter la commande cat et d’autres commandes que Maven en donnant le chemin d’accès absolu à la commande:

Enfin, vous avez peut-être remarqué que nous avons déclaré les variables d’environnement M2_REPO et MAVEN_OPTS sous forme d’instructions Docker ENV avec des valeurs par défaut pour tous les paramètres importants. Elles peuvent être surchargées via l’option -e dans la commande de démarrage de docker.

Tester ses Images Docker

Comme pour tout autre type de code source, il est possible de créer des suites de tests pour ses images Docker et Dockerfiles. Pour les images Docker eXo CI, nous utilisons Goss à travers son wrapper dgoss.

  • Goss est un outil, basé sur YAML, pour valider la configuration d’un serveur
  • dgoss est une enveloppe autour de Goss qui vise à apporter la simplicité de Goss aux conteneurs Docker.

La première étape consiste à créer un fichier YAML pour décrire ce que vous souhaitez tester dans votre conteneur Docker. Il existe des exemples en ligne qui peuvent aider à créer ce fichier de configuration, mais cela peut également être généré par la ligne de commande de goss.

Par exemple, nous voulons vérifier que certains fichiers de configuration Maven existent dans le conteneur. Nous voulons également être sûr que la commande mvn –version est conforme aux versions Maven et JDK installées dans le container.

goss.yaml

Ensuite, pour exécuter ces tests, il suffit simplement d’exécuter une ligne de commande via  dgoss:

 

CodeConclusion

Si vous êtes intéressés pour tester ou utiliser ces images Docker:

N’hésitez pas à nous faire part de vos commentaires ou à proposer vos idées.

Prochaine étape

Maintenant que nous avons créé nos propres Images Docker pour toutes nos environnements de build de l’intégration continue, nous vous expliquerons dans le prochain article (Partie 2), comment utiliser ces images dans un environnement de développement local quel que soit votre système d’exploitation.
Découvrez comment eXo Platform peut vous aider à transformer votre entreprise!

Postes Connexes

Je suis Software Factory Manager chez eXo. Je suis responsable des composants de la forge logicielle eXo (Jenkins CI, GitHub, Nexus, Sonar...) et du processus automatisé de Releases. J'aide les développeurs à utiliser au quotidien des processus de développement le plus simple et automatisé possible. Passioné par l'IT et l'Open Source, je contribue de différentes façons à des projets Open Source (participation à des conférences, écriture d'articles techniques...). J'ai également écrit un livre sur Apache Maven 3.

Commentaires
Laisser une réponse

Votre adresse email ne sera pas publiée.

j’ai pris connaissance et j’accepte la politique de confidentialité En savoir Plus

Vous pouvez utiliser ces HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

HTML Snippets Powered By : XYZScripts.com