Régulièrement, nous allons publier sur notre blog des articles rédigés par les équipes techniques, qui donnent vie à Keecker, dans nos locaux au coeur de Paris. Bonne lecture !

----------------------------------------------------------------------------------------

De Jenkins vers Gitlab CI

 

Keecker n’est pas une entreprise comme les autres. Non seulement nous construisons un robot innovant à partir de rien mais nous développons et publions des applications iOS et Android de qualité. Ces projets sont interdépendants, ont leur propre complexité, dépendance et requièrent des connaissances différentes. Comme vous pouvez l’imaginer, nous avons un processus de build particulièrement complexe.

Historiquement, Jenkins a été notre solution pour builder des projets en local. Mais faisant face à un nombre de projets et de développeurs toujours plus importants, nous avons atteint un point de non retour, nous avons besoin d’un meilleur système d’intégration continue.

Suite à notre migration vers Gitlab, nous avons décidé de tester Gitlab CI pour remplacer notre pipeline d’intégration continue. Dans l’espoir de pouvoir simplifier le processus de build mais aussi de rendre le tout plus solide pour favoriser les itérations.

Après quelques semaines d’utilisation, nous avons décidé de partager nos retours, les avantages et les inconvénients de Gitlab CI.

 

“Move fast and break things”

 

Jenkins était définitivement une bonne solution pour débuter. Bien documenté, grosse communauté, Jenkins fut parfait pour nos débuts mais devint rapidement un problème pour plusieurs raisons.

 

Builds tres lents.

Nous avions seulement trois machines pour effectuer nos builds. Ce qui signifie qu’à chaque fois que trois builds concurrents étaient lancés, les suivants devaient attendre. Pour une équipe de 15 développeurs, ça commençait à faire beaucoup.

Une façon de régler ce problème était de configurer plus de machines mais nous n’avions pas envie de créer une usine dans nos petits locaux.

De plus, notre instance Jenkins tournait sur une machine de build, ce qui signifie qu’en période de build, le dashboard de Jenkins pouvait prendre plusieurs minutes à se charger. Héberger une instance Jenkins signifie aussi le maintenir et garder les plugins à jour pour éviter les failles de sécurité.

Enfin, non seulement les builds étaient lents, mais dans le cas d’un échec, il nous était impossible d’en identifier rapidement la raison.

 

Mauvaises conditions de travail

Du côté des développeurs, l’utilisation de Jenkins devenait désagréable.

Nous utilisions un seul Dockerfile pour différents projets. Il devenait compliqué de savoir quel projet avait besoin de quel package ou dépendance. Un simple changement de package pouvait casser un projet mais pas un autre.

 

Un développeur à Keecker essayant de changer un Dockerfile

Un développeur Keecker essayant de changer un Dockerfile
 

Si le Dockerfile n'était pas suffisant, nous devions gérer un mélange de configurations locales et Docker. Certaines variables d’environnement étant initialisées dans le Dockerfile, d’autres dans le .bashrc. La tâche était complexe.

Au final, faire un build quotidien pouvait être très frustrant. La seule façon de régler les problèmes rencontrés était de passer par les logs. Il était alors très compliqué d'itérer régulièrement et d’avancer rapidement dans nos tâches.

En conséquence, vu le nombre grandissant de projets et la stagnation du nombre de machines, nous avons décidé de changer de solution d'intégration continue. Nous avions besoin de plusieurs machines, avec des configurations spécifiques aux projets, le tout avec une meilleure interface. Gitlab CI était la solution.

 

Comment Gitlab CI fonctionne (chez Keecker)?

 

Gitlab CI fonctionne principalement avec deux entités: Gitlab runner et le fichier gitlab-ci.yaml.

Un Gitlab Runner est chargé de prendre les jobs et de les lancer. Chez Keecker, nous en avons de trois types:

1) “Gitlab shared runners”, ils sont gratuits mais ont un usage limité.

2) Les VM de Google Cloud Platform, qui sont évolutives et complètement configurables.

3) Les machines physiques, qui nous permettent d'utiliser des appareils physiques et sont nécessaires au build iOS.

 

Le fichier gitlab-ci.yaml a pour unique but de décrire comment builder le projet: chez Keecker, nous utilisons Docker, ainsi la plupart des fichiers gitlab-ci.yaml commencent avec une image Docker.

Avoir une image Docker plutôt qu’un Ubuntu classique nous permet de gagner du temps de build. Tous les packages requis, les SDKs ainsi que les variables d’environnement sont installés dans notre image Docker. Ainsi, nous n’avons pas besoin de les installer au début de chaque job.

Ensuite, on definit nos différents jobs:

On retrouve alors cette arborescence dans Gitlab:

Simple n’est ce pas?

Suite à la migration de cinq de nos projets sur Gitlab CI, nous avons déjà des retours sur ce qui fonctionne (ou pas) et les difficultés à venir pour les prochains builds.

 

Pours

- Builds plus rapides

Les améliorations de performance que nous observons sont principalement liés au fait que nous installons ou ne clonons que ce qui est nécessaire. Il n’y a qu’une seule image Docker et un seul fichier gitlab-ci.yml pour chaque projet. Ensuite, la parallélisation des builds nous permet également de gagner beaucoup de temps. Le build d’application iOS n’affectera jamais celui de l’Android.

- Processus plus agréable pour les devs

Avoir des jobs à la fois plus spécifiques et plus petits nous permet de voir rapidement d'où vient le problème et de relancer un build si nécessaire. Avoir le tout sur un simple site est également une grande plus-value : en un clic, les merge requests sont testées.

 - Evolutif

Les machines de Google cloud platform nous permettent de “scaler” rapidement et d’allouer plus de ressources si nécessaire de manière transparente.

- Plus facile a maintenir

Avant, changer le job Jenkins impactait directement chaque branch. Désormais, le fichier gitlab-ci.yaml est versionné dans le même dépôt que les projets et fonctionne avec les branches. En clair, chacun peut changer le fichier de configuration à sa guise sans risque de casser le travail des autres.

 

Contres

- La configuration de Gitlab sur Kubernetes est loin d'être facile.

Gitlab propose une integration avec Kubernetes en “un clic” mais cela ne permettait pas d’utiliser nos images Docker privées. Nous avons donc dû installer manuellement Kubernetes. Un procédé qui n’est pas bien documenté. Nous avons fait face à de nombreux problèmes non résolus par Gitlab. Aujourd’hui, nous avons encore des problèmes de cache avec Gradle.

- Docker pull à chaque étape

Étant donné que chaque job est indépendant, nous recommençons de zéro à chaque fois, en “pullant” une image Docker et en réinstallant les packages. C’est pourquoi nous avons décidé d’avoir une image Docker spécifique à chaque projet et de limiter le nombre de clones ou de packages dans le .gitlab-ci.yml.

- Tester plusieurs projets simultanément

Comme nous l’avons dit en introduction, nous avons plusieurs projets qui sont interdépendants. Ils ont des dépôts différents mais ont besoin parfois d'être buildés ensemble ou au moins d'être validé ensemble. Gitlab CI est parfait pour un dépôt unique. Nous allons devoir trouver une solution pour faire en sorte de builder ces projets interdépendants.

 

Un pas en avant

 

Keecker a fait en sorte de proposer rapidement une expérience nouvelle à ses utilisateurs. Mais nous avons accumulé une dette technique et il est devenu nécessaire de changer notre système de build. Avec cette migration vers Gitlab CI, nous devenons plus mature en matière d’infrastructures et nous pouvons sortir des mises à jour plus rapidement.

Après tout, Keecker étant un robot intelligent, nous nous devions de rendre notre système de build plus efficace pour rendre nos robots d’aujourd’hui et de demain plus performants.

 

Le nouveau système de build de Keecker