Accueil Nos publications Blog Retour d’expérience sur GoCD

Retour d’expérience sur GoCD

Un mot d’introduction

Nous avions vu dans le premier article de cette série, les concepts fondamentaux du Continuous Delivery d’une part, puis l’implémentation de ces concepts par l’outil GoCD que nous avions par la suite détaillée.

Dans cet article, je vous propose un retour d’expérience sur la mise en place et l’utilisation de l’outil, en mission clientèle.

Nous verrons alors ce qui a motivé ce choix, comment nous avons appréhendé son architecture, son industrialisation, en passant par les difficultés rencontrées mais aussi les points positifs.

Retour d’expérience sur la mise en place de GoCD

Contexte client

À l’heure où j’écris cet article, une large transformation DevOps a déjà été amorcée depuis quelques temps chez mon client.

Certains outils et pratiques commencent à émerger, les responsabilités changent petit à petit, l’équipe de développement obtient l’accès à de plus en plus d’environnements et de ressources jusque-là alors réservées à des équipes dédiées comme les équipes socle/sécurité ou encore l’usine logicielle.

Cela constitue un énorme changement pour des développeurs qui jusque-là disposaient d’outils et de plateformes entièrement hébergés par une équipe, qui gère ces outils à plein temps.

Au-delà des outils, ce sont les pratiques qui changent : nous (équipes de réalisation) maîtrisons de plus en plus la chaîne complète d’intégration et de build, jusqu’à la réalisation d’un premier déploiement en production entièrement automatisé !

Note : Attention, pouvoir réaliser plus d’actions comme déployer en production ne veut pas dire que l’on peut tout contrôler. Cela ne se fait pas sans un accompagnement des équipes opérationnelles et de sécurité, ni sans passer par la mise en place d’une matrice de responsabilités (élaboration d’un RACI, mise en place d’un RBAC – Role-Based Control Acess)

Impliquer toutes les équipes dans l’élaboration des processus, la définition des conventions de nommage, est déjà à mon sens un très grand pas vers la transformation DevOps.

Pourquoi ce choix ?

Revenons à notre outil de CI/CD.

Nous en avons discuté dans la 1ère section, délivrer un projet de manière rapide, fiable et reproductible passe par la mise en place d’un outil d’automatisation.

Comme beaucoup d’équipes, nous nous sommes vite tournés vers Jenkins, qui propose dans sa version 2 d’élaborer des pipelines grâce à un DSL (Domain Specific Language) en Groovy.

Après quelques essais, l’un de mes coéquipiers m’a présenté GoCD.

Sans entrer dans les détails jusqu’à aller comparer les 2 outils, GoCD nous a séduits sur le moment et semblait tout à fait adapté à notre workflow de développement.

Son apparente simplicité de mise en œuvre et les fonctionnalités couvertes nous ont aidés à figer ce choix par la suite.

Une fois les essais en local terminés, nous nous sommes employés à industrialiser l’outil, avec un seul objectif :

Rendre le déploiement de la solution entièrement automatisé et reproductible au cas où la plateforme viendrait à tomber.

Industrialisation

Pour réaliser cela, nous avons d’abord établi une levée de risques au moyen d’ADR (Architectural Decision Records).

Ces ADR, que l’on a consignés dans un dépôt Git, portaient principalement sur les points suivants :

  • Hébergement et run des services GoCD

Notre architecture client - serveur GoCD doit-elle être installée sur une VM nue, Dockerisée, ou les deux ?

À noter que certains de nos agents (ayant une fonction de déploiement) ont été installés sur des VMs nues, provisionnées par Ansible

  • Stockage et devenir des données

Où seront stockées les données inhérentes au fonctionnement de l'outil ?

Comment gérer le backup et la récupération de ces données ?

  • Exposition de la WebUI

Comment rendre accessible le service aux autres membres d'équipe ?

Dockerisation

La solution la plus évidente dans notre contexte était de dockeriser les services go-server et go-agent, en profitant des possibilités qu’offrait notre plateforme Docker Swarm EE.

Entre autres :

  • Réplication des services
  • Haute disponibilité du service
  • Scalabilité des agents
  • Communication via un réseau overlay Docker
  • Packaging des binaires et autres outils sous forme d’images

Nous pouvons retrouver les images gocd-server et gocd-agent sur Docker Hub.

Note : préférer l’image embarquant une distribution alpine pour les agents, plus petite, mais change la façon d’installer les paquets

Nous sommes donc partis sur ces 2 images Docker, par-dessus lesquelles nous avons empilé nos propres layers, comme par exemple la configuration d’un proxy d’entreprise, l’installation de Docker, nos outils de builds, etc.

Pour faciliter la création et le déploiement de ces images, nous avons créé un Makefile avec 3 cibles :

  • build : construction des images Docker (commandes docker build)
  • push : publication des images Docker (commandes docker push)
  • deploy : déploiement du packaging (commandes docker stack deploy)

Ainsi, grâce à un fichier docker-compose.yml comportant les 2 services GoCD, nous pouvons déployer l’architecture complète, soit 1 replicat du serveur et 3+ replicats de l’agent.

Grâce aux réseaux overlay Docker et au mapping de ports, nos agents peuvent facilement communiquer et s’enregistrer auprès du serveur GoCD.

Gestion des pipelines

Une fois notre serveur et nos agents provisionnés, jetons un coup d’œil à l’industrialisation de nos builds, à savoir la création des pipelines.

Pour rappel, GoCD propose une WebUi permettant de créer des pipelines :

Source : Documentation GoCD

Bien qu’intuitif, ce procédé n’entre pas dans notre idéal de everything as code.

En effet, un pipeline créé par la WebUi est sauvegardé en tant que structure XML dans le fichier de configuration du serveur (appelé cruise config).

Ce fichier peut éventuellement être versionné sous Git, mais nécessite une mise à jour manuelle de la part de l’utilisateur dans le module d’administration de la WebUi.

Pas terrible, surtout que GoCD maintient pour nous un audit des changements effectués sur ce fichier, grâce à un dépôt Git interne.

De plus, le format XML n’est pas des plus simples à manipuler et devient vite très verbeux.

Alors comment rendre tout ceci un peu plus flexible, user-friendly et maintenable ?


C’est ici qu’intervient le module gocd-yaml-config-plugin.

Implémenté par l’utilisateur Github @tomzo, il a été intégré au noyau de GoCD.

À l’heure où j’écris ces lignes, le plugin est encore en développement actif.

Il permet grâce à un valideur syntaxique YAML de déclarer tous ses pipelines dans ce format, ce qui va nous ouvrir les portes du pipeline as code et donc nous permettre de pouvoir bien séparer la définition des builds de leur exécution.

Ainsi, la gestion du pipeline de déploiement d’un projet peut être stockée et gérée au plus près du code !

Du côté du serveur GoCD, voici comment cela se passe :

Source : Documentation GoCD

Chaque pipelines as code, (ou groupe de pipelines) est déclaré dans la configuration XML sous un dépôt Git à la main de l’utilisateur.

Le serveur va alors régulièrement effectuer du polling sur chaque dépôt et créer ou modifier en conséquence les pipelines pour les faire apparaître dans la WebUi.

À noter que les pipelines as code ne sont pas modifiables via la WebUi. Chaque modification doit être poussée dans le dépôt Git, ce qui est l’objectif souhaité

Anatomie d’un pipeline as code

Voyons maintenant à quoi ressemble concrètement un pipeline minimaliste, déclaré en YAML :


mypipe:
  group: mygroup
  materials:
    mygit:
      git: https://example.com/mygit.git
  stages:
    - build:
        jobs:
          build:
            tasks:
             - exec:
                 command: make

Nous retrouvons ici les notions vues précédemment : materials, stage, jobs et tasks.

De nombreuses possibilités sont fournies avec ce plugin, nous retiendrons qu’il est possible de faire presque tout ce que la WebUi permet, au delta d’un point important que nous allons voir ci-après.

Pour d’autres exemples, je vous invite à consulter le Github

Ce qui a bien, et moins bien marché

Il est temps maintenant pour moi de dresser un bilan de tout cela, et établir un retour sur ce qui a été un succès, mais aussi sur les difficultés rencontrées.

Utilisation au quotidien

Tout d’abord, du point de vue des membres de l’équipe, les retours sont plutôt positifs au niveau de l’utilisation de la WebUi.

L’interface est agréable, la vue VSM (Value Stream Map) étant l’un des gros points forts de la solution pour manipuler une chaîne complète de déploiement tout en maîtrisant d’un coup d’œil la traçabilité de son projet.

Source : Documentation GoCD

L’accès au détail de chaque étape d’un pipeline est très intuitif, de même que la visualisation des artéfacts produits (exposés au moyen d’un onglet custom).

Enfin, il est très facile de retrouver à quelle étape de la chaîne de déploiement se situe un commit, grâce aux fonctionnalités de filtre.

C’est aussi cette simplicité qui fait la force de GoCD.

Maintenance de la solution industrialisée

Le projet qui maintient les sources de construction de cette architecture a été un plus pour faciliter son déploiement.

Comme expliqué précédemment, les 3 cibles make constituent les seules commandes à lancer par les développeurs pour mettre à jour et déployer les images Docker de façon standardisée.

De plus, le service GoCD supporte très bien le rechargement à chaud des agents, la mise à jour des plugins, etc.

Enfin, la mise à jour de la version du serveur et des agents se fait plutôt bien, un simple upgrade des images Docker suffit, à condition bien sûr de prendre en compte les éventuels éléments du changelog qui ne seraient plus compatibles avec le format des données de la version actuelle (ce point n’a pas été rencontré).

Quelques points d’attention, notamment :

  • Veiller à bien versionner le fichier XML cruise config pour une raison simple : cela permet de conserver toujours le même ID d’enregistrement du serveur à chaque déploiement

Cela permet également de conserver toutes les déclarations de dépôts contenant les pipelines as code.

  • Conserver le fichier cipher dans le dépôt Git, pour éviter d’avoir à changer tous les mots de passe cryptés dans les pipelines

Pour une question de sécurité, ce fichier doit être protégé par un mécanisme de chiffrement (ansible-vault par exemple).

  • Veiller à sauvegarder certains répertoires, notamment le dossier /godata du serveur GoCD qui contient toute cette configuration

Il est arrivé que nous ayons perdu le volume Docker attaché au service gocd-server, ce qui a eu pour conséquence pour nous de perdre tout l’historique des builds, ainsi qu’une partie de la configuration (entre autres le fichier cipher).

Il a été facile de remonter la plateforme de zéro grâce aux sources du projet, mais il a fallu tout de même modifier tous les pipelines pour mettre à jour les valeurs des variables sécurisées avec le nouveau cipher.

  • Enfin, comme pour toute solution de CI/CD, prévoir un espace disque assez conséquent, selon la taille et la fréquence de vos builds

Pour avoir un ordre d’idée, nos 6 micro-services packagés sous forme de FatJar SpringBoot font ~130Mo chacun.

Les commits réguliers sur develop déclenchent un certain nombre de constructions chaque jour, et les artéfacts sont conservés pour être transférés ensuite aux stages de construction des images Docker

Autrement dit, nous sommes très vite arrivés à saturation de l’espace disque alloué à notre plateforme (~80Go par nœud Docker).

De plus, notre plateforme Docker n’est pas faite pour accueillir des services ayant besoin de volumes, mais plutôt faite pour des services stateless. De ce fait, aucune réplication n’étant réalisée entre les nœud du cluster, nous avons dû affecter un nœud spécifique à nos déploiements de stacks.

Néanmoins, cette plateforme a simplifié pas mal de choses, notamment l’exposition du service sur le canal HTTPS grâce au service de Routing Mesh de Docker Swarm.

Conception des pipelines

D’un point de vue développeur, la manipulation de fichiers YAML dans des dépôts Git a permis de gérer les pipelines comme un projet, avec tout ce qui s’y rapporte : versioning, merge request, association à des tickets JIRA, etc.

On notera l’absence de gestion des feature branch, comme pourrait le faire un Jenkins, ou un Gitlab. Il est possible de gérer plusieurs branches d’un projet en parallèle dans GoCD, mais cela demande un effort de configuration manuelle

Le format YAML permet d’annoter le code avec des commentaires et reste assez lisible.

En revanche, l’indentation des fichiers doit être rigoureuse et respecter une certaine structure dans la déclaration des objets.

Le gros inconvénient ici est qu’il n’est pas possible de valider directement la cohérence de son pipeline avant de l’avoir commité et donc avant que le plugin n’en ait fait la validation sur demande du serveur.

Ce point constitue une grosse perte de temps, bien que le mécanisme de polling qui scrute les modifications des dépôts Git soit fixé à 1 minute environ.

Note : depuis peu, la dernière version du plugin embarque une CLI permettant justement de valider la syntaxe et la cohérence de ses pipelines, au moyen d’un IDE en ligne de commande. Ceci est une belle avancée, sachant que cet IDE a été embarqué dans une image Docker, que l’on pourra facilement lancer si l’on dispose d’un environnement de développement avec Docker

Exemple tiré de la documentation du plugin gocd-yaml-config-plugin :


$ docker run -ti --rm --volume $(pwd):/ide/work tomzo/gocd-yaml-ide:0.8.6 bash

Puis une fois dans le conteneur :


$ ide
$ watch gocd-yaml syntax ci.gocd.yaml

Autre point noir de la solution : l’aspect DRY (Don’t Repeat Yourself).

De mon point de vue, ceci constitue le plus gros frein à l’adoption de la solution.

GoCD offre via la WebUi la possibilité de créer des templates de pipelines, ce qui permet de ne pas se répéter lorsque l’on va dupliquer ces pipelines pour d’autres projets similaires.

Malheureusement, il n’est pas possible aujourd’hui de déclarer ces templates via du YAML, et ainsi centraliser cette configuration dans nos dépôts Git.

Nous avons dû faire avec ce manque, en répétant certaines parties du code, tout en essayant d’être le plus générique possible (les spécificités étant portées au maximum par les paramètres de pipelines et les variables d’environnement).

En conclusion

En conclusion, je dirais que GoCD est un outil qui mérite notre attention. L’outil est certes encore jeune sur certains aspects, mais propose néanmoins un beau panel de fonctionnalités, dont certaines non abordées dans ce retour d’expérience, comme la promotion d’artéfacts, la comparaison de builds, la gestion des utilisateurs/rôles, l’intégration avec Kubernetes…

Aujourd’hui, la solution GoCD est remise en question sur notre mission. En effet, le nombre de micro-services à construire et à déployer allant croissant sur notre projet, la déclaration répétitive des pipelines est devenue plus que fastidieuse.

Le choix de notre plateforme d’hébergement (Docker Swarm) qui était un atout au départ, est vite devenu une contrainte à cause de l’espace disque, de plus la plateforme n’était pas faite pour héberger ce type de service.

Au vu de ces éléments, devons-nous considérer la migration de notre infrastructure de CI/CD vers un autre outil, sous peine d’avoir à revoir tous nos pipelines et toutes nos pratiques ?

Cette réflexion est encore d’actualité, n’hésitez pas à rebondir sur la question.

Happy Delivery !

Ressources

© SOAT
Toute reproduction interdite sans autorisation de l’auteur.