Comment nous déployons notre application web avec GitLab-CI

par Pierre de La Morinerie, le 26 août 2016 | 15 commentaires

Le monde du rail est en perpétuelle évolution. Tous les jours de nouveaux tarifs apparaissent, des trains sont ouverts à la vente, une gare est fermée, une autre est ouverte. Pour suivre cette évolution, et vous faire profiter des dernières améliorations et correction de bugs, l’application web de Captain Train est mise à jour continuellement, jusqu’à plusieurs fois par jour.

Si vous vous êtes un jour demandé comment nous compilons et déployons tout ça sans accroche, montez à bord, et prenez place pour un aperçu technique de notre système de déploiement continu.

GitLab at Captain Train

De Jenkins à GitLab-CI

Historiquement, notre appli web était compilée par Jenkins. Une solution fiable et éprouvée – qui interrogeait nos dépôts Git chaque minute, et lançait les tâches de compilation appropriées sur les branches d’intégration et de production.

Nous avons récemment migré ces tâches vers un nouveau système. Vous vous en souvenez peut-être, nous utilisons une instance auto-hébergée de GitLab pour héberger notre code. C’est un système mature, open-source – qui dispose également d’un outil d’intégration continue : GitLab-CI.

Pour ceux qui connaissent, ça ressemble à Travis – mais complètement intégré : il suffit d’ajouter un fichier .gitlab-ci.yml à la racine d’un projet, et GitLab va automatiquement compiler l’application de la manière spécifiée.

Cette intégration apporte plein de bonnes choses d’un coup.

Des builds en béton

Nos tâches Jenkins étaient toutes exécutées sur un seul serveur, qui avait connu de meilleurs jours. Ce manque de ressources finissait par rendre les tâches lentes et instables. Par exemple nous avons pris plusieurs fois PhantomJS en flagrant délit de plantage aléatoire pendant les tests : apparemment il n’aime pas trop être lancé plusieurs fois sur la même machine en parallèle. Et quand un processus PhantomJS plante, il a tendance à entrainer tous les autres qui tournent au même moment à sa suite. Super.

La première étape de notre migration a donc été d’isoler les builds dans des conteneurs Docker. De cette manière :

  • Chaque build est isolée des autres. Ça évite (entre autres) que des processus différents se fassent planter l’un l’autre, ou essaient d’utiliser les mêmes ports, ou d’écrire dans les mêmes fichiers temporaires.
  • On peut facilement compiler le même projet sur différentes architectures. Et ça tombe bien, parce qu’on en a parfois besoin pour supporter plusieurs versions de Debian.
  • Chaque projet a plus de contrôle sur la configuration de son environnement de compilation. Plus besoin d’aller demander à un sysadmin de mettre à jour un SDK sur la machine partagée.

Changer d’échelle

GitLab-CI permet d’ajouter de nouveaux serveurs de compilation très facilement. Et maintenant que les tâches sont exécutées dans des conteneurs Docker, plus besoin de configurer l’environnement de développement de chaque nouveau serveur : n’importe quelle machine fera l’affaire.

Une fois qu’un nouveau serveur de compilation est déclaré, il est automatiquement intégré au service : GitLab-CI va sélectionner la machine la plus disponible au lancement de chaque nouvelle tâche. Il est même possible de déclarer sa propre machine comme serveur pour lancer les tâches de compilation localement.

Nous avons déjà réduit les délais de compilation en ajoutant un nouveau serveur bien plus puissant – et cette migration aurait été bien plus difficile à faire sous Jenkins. Même si on optimise régulièrement les performances des tests, parfois doubler un bon coup la quantité de RAM et de CPU est juste la meilleure solution.

Ouvrir les frontières

Avec Jenkins, la configuration des tâches de compilation est stockée dans un outil externe, protégé par des droits séparés. Pour éditer la configuration il est nécessaire d’avoir les bons accès – et même après il n’est pas évident de trouver comment faire.

En revanche la configuration des tâches GitLab-CI est déterminée uniquement par le fichier .gitlab-ci.yml à la racine du projet. Ça signifie qu’on peut l’éditer avec les outils habituels, le versionner avec git, faire des merge requests, et tout.

Et puis maintenant, pour activer l’intégration continue sur un projet, plus besoin de demander une permission ou des accès spéciaux à qui que ce soit. Ça diminue les freins aux bonnes pratiques de développement, et c’est clairement une chose à laquelle on est attaché : c’est bon pour la qualité, et bon pour le moral des développeurs.

Tester sans se presser

GitLab-CI permet de faire facilement tourner les tests sur les branches d’une Merge request (l’équivalent d’une « Pull request » chez GitHub). Quelques lignes ajoutées au .gitlab-ci.yml, et on fait tourner les tests à chaque fois que du nouveau code est poussé.

Still testing – but just hit the "Merge When Build Succeeds" button and move on

Les tests tournent encore – mais un clic, et on peut retourner mettre des gamelles au baby.

Ça active automatiquement une zone de statut indiquant l’état des tests, le super bouton « Merger automatiquement dès que les tests passent » – et surtout, maintenant que les branches sont testées avant d’être acceptées, beaucoup moins de casse sur le projet.

Ready to merge.

Supergreen 👌

Tout plaquer et se mettre au vert

Toutes les tâches de compilation sont résumées dans une page synthétique, que GitLab appelle les « Pipelines ». Cela permet de voir facilement quelles sont les tâches qui échouent, et à quel stade. Et puis rien ne vaut ce sentiment de satisfaction paisible de constater que tous les indicateurs sont au vert.

All Pipelines are green, ready to deploy.

Tous les voyants sont au vert : feu.

Bref.

Au final nous avons trouvé l’expérience très positive. Une fois passée la partie un peu fastidieuse de migration des tâches dans Docker, l’intégration avec GitLab-CI s’est faite comme sur des roulettes. Et ça nous a donné gratuitement tout un tas d’indicateurs, de fonctionnalités et d’intégrations sympa. 10/10, on refait ça quand vous voulez 👍

Notre équipe Android a d’ailleurs également migré son processus sur GitLab-CI, et s’en sert maintenant pour générer les APK d’intégration et de production.

Si le sujet vous intéresse, il y a un bon aperçu des fonctionnalités de GitLab-CI sur le site officiel, ainsi que quelques exemples pour montrer à quoi ressemble un fichier gitlab-ci.yml.


15 commentaires

Bonjour,

Merci pour ce retour fort intéressant avec des exemples pris en production.

par Soliman Hindy, le 26 août 2016 à 11h12. Répondre #

Bonjour,
Merci pour l’article et la description.

À moindre échelle, on est sur une base Github + Codeship qui fait à peu près la même chose. Le choix d’une solution maison est purement économique ou vous avez des besoins spécifiques ? (Uniquement pour votre plateforme Web, je ne suppose rien sur le côté Android que je ne connais guère 🙂 )

par Stan, le 26 août 2016 à 11h23. Répondre #

Initialement notre choix de migrer de Github Enterprise à Gitlab s’est fait essentiellement en fonction du prix : en dépassant le seuil de 20 personnes, ça commençait à faire cher.

Cela dit on voulait impérativement un système auto-hébergé (parce que c’est la culture de la maison, et pour la confidentialité). Et aussi l’aspect Open-source de Gitlab nous a bien plu : on a pu améliorer des fonctionnalités et corriger des bugs qui nous gênaient, et cette maîtrise de l’outil est assez agréable.

Après on n’a pas de besoins très spécifiques ; et il y a beaucoup d’autres manières d’assembler une solution qui fonctionne 🙂 Celle-là fonctionne bien pour nous, en tout cas.

par Pierre de La Morinerie, le 26 août 2016 à 13h55. Répondre #

Votre super article va sûrement donner envie à tout ceux qui ne connaissent pas GitLab-CI et Docker d’essayer. Merci !

À propos de Docker, utilisez-vous les nouveaux docker executors ? les shell executors ? Par exemple, pouvez-vous ajouter un paquet Debian aux builds avec juste une merge request ou faut-il mettre à jour l’image manuellement ?

par Bertrand, le 26 août 2016 à 16h22. Répondre #

Pour l’instant on n’utilise pas les Docker-executor. On reste aux commandes shell classiques – simplement la première étape de chaque script est de construire ou de récupérer une image Docker, à l’intérieur de laquelle faire tourner notre build.

C’est un choix fait essentiellement pour faciliter la transition ; et aussi c’était la solution la plus simple pour ré-utiliser nos variables d’environnement à l’intérieur des conteneurs Docker (un `.env`-file, et le tour est joué).

Cela dit dans le futur on essaiera certainement de voir si ces processus peuvent utiliser les Docker-executors malgré tout.

par Pierre de La Morinerie, le 29 août 2016 à 11h30. Répondre #

Merci pour ces précisions ! Je pense que notre système de build doit ressembler au votre. Avoir le Dockerfile dans le même dépôt que le logiciel est bien pratique et je n’ai pas trouvé un moyen de faire aussi bien avec les docker executors.

par Bertrand, le 29 août 2016 à 11h58. Répondre #

Bonjour belle article en effet.
Qu’est ce qui vous a déplu dans Jenkins ? en dehors du fait que vous aviez besoin d’un serveur intégré à l’application ?
Car le runner Jenkins est implémenté dasn beaucoup d’application tierce et permet de creer des tickets de facon automatique par exemple.
D’ailleurs c’est quelle version que vous aviez de Jenkins ? la 2.1 ?

par Sylvain, le 26 août 2016 à 20h06. Répondre #

On avait un Jenkins 1, qui était effectivement assez ancien, et n’incluait pas les dernières nouveautés sympa de Jenkins 2. Et effectivement tout ce que nous avons fait là est sans doute très faisable avec une version récente de Jenkins.

Ce qui nous a convaincu de migrer à Gitlab-CI est qu’il n’y a pas besoin d’un administrateur système pour commencer : chaque développeur peut commencer à créer son système de build sans avoir rien à demander à personne, progressivement, sans avoir à migrer tous les projets de Jenkins d’un coup. Et du coup ça s’est fait comme ça : parce que les développeurs eux-même avaient la possibilité de le faire sans rien casser.

D’autre part l’intégration à Gitlab, aux issues et aux Merge Requests est vraiment agréable. C’est certes moins flexible que de configurer des webhooks dans Jenkins pour se faire son réseau de notifications internes – mais on gagne vraiment en simplicité.

Et enfin on a eu l’impression que Gitlab-CI avance vraiment bien en ce moment : il y a beaucoup de travail qui est fait, des nouvelles fonctionnalités chaque mois… Ça nous a semblé un bon outil sur lequel investir 🙂

par Pierre de La Morinerie, le 29 août 2016 à 11h39. Répondre #

Félicitations. Bon, on va y arriver à migrer le bépo vers gitlab, surtout depuis que les tableaux de gestion des tickets sont disponibles, mais ce serait tellement plus élégant avec un gitlab traduit en français…

par nemolivier, le 30 août 2016 à 12h11. Répondre #

Bravo pour cette migration.

J’ai eu utilisé des infra avec gerrit (Perte de la décentralisation de git) et de jenkins avec des instances amazon pour les builds.

Votre solution offre pas mal de souplesse au final. Car des images docker vous pouvez en faire de toute sorte. D’ailleurs pour docker vous utilisez un swarm pour rajouter de la puissance ou vous rattachez seulement des serveurs avec un docker-engine dessus ?

En tout cas bravo et c’est cool de voir une entreprise qui explique sur ses workflow.

par Hydrog3n, le 30 août 2016 à 14h53. Répondre #

Non, nous n’utilisons pas les fonctionnalités d’auto-scale de GitLab avec un swarm derrière : ce sont simplement des serveurs rajoutés à la main avec un docker-engine. Comme c’est une opération qui n’arrive que tous les quelques mois, ça reste raisonnable.

par Pierre de La Morinerie, le 30 août 2016 à 14h55. Répondre #

Pierre l’a déjà dit mais pour détailler un peu plus: nous n’utilisons pas Gitlab pour lancer des instances « live » de nos services.
Les conteneurs docker servent donc simplement à faire tourner les étapes de build, test et packaging. Ainsi un docker engine par runner Gitlab est suffisant puisqu’ils sont complètement indépendant.

par Paul Bonaud, le 30 août 2016 à 16h15. Répondre #

Bonjour,

Merci à vous pour ce retour !
Pouvons-nous également savoir quelle intégration continue est utilisée pour l’appli iOS ? Toujours sur Jenkins ? Avec XCode Server ^^ ?

par Rémi, le 30 août 2016 à 16h00. Répondre #

Au début du projet, nous utilisions Jenkins, mais depuis un peu plus d’un an, nous sommes passés sur Xcode Server, qui a l’avantage de demander très peu de maintenance. Depuis peu, nous utilisons aussi gitlab-ci, mais uniquement pour faire tourner les tests sur les Merge Requests.

par Nicolas Bouilleaud, le 30 août 2016 à 16h17. Répondre #

Merci pour ces informations

par yachts-booking, le 24 avril 2017 à 16h59. Répondre #

Ajoutez votre commentaire

Requis

Requis (caché)

Facebook

Twitter