Cinq conseils sur les dépôts favorisant l'intégration continue

Sarah Goff-Dupont
Sarah Goff-Dupont
Retour à la liste

Si vous êtes abonné à Atlassian, vous savez que l'intégration continue (« CI ») est l'une de nos forces, sans Git, mais plus encore lorsque vous combinez les deux. Aujourd'hui, je souhaiterais vous donner quelques astuces pour optimiser les interactions de votre système de CI avec votre dépôt, ce qui est le point de départ.

1 : Éviter de tracker les fichiers volumineux dans votre dépôt

Vous entendrez souvent ce commentaire à propos de Git : « Évitez de placer des fichiers volumineux (fichiers binaires, fichiers multimédias, artefacts archivés, etc.) dans votre dépôt ». En effet, lorsque vous ajoutez un fichier, il reste dans l'historique du dépôt, ce qui signifie que chaque fois que le dépôt est cloné, cet énorme fichier l'est lui aussi. Extraire un fichier de l'historique du dépôt est également très délicat. Cela revient à pratiquer une lobotomie sur votre base de code. Cette extraction chirurgicale d'un fichier affecte également l'historique complet du dépôt. Vous ne pouvez donc plus clairement distinguer quels changements ont été apportés et à quel moment. Ce sont effectivement de bonnes raisons d'éviter les fichiers volumineux en règle générale.

C'est on ne peut plus important si vous effectuez une CI.

À chaque génération, votre serveur CI doit cloner votre dépôt dans le répertoire du build de travail. Si votre dépôt est alourdi par des artefacts volumineux, le process est ralenti et les développeurs doivent attendre plus longtemps les résultats du build.

OK, parfait. Mais qu'en est-il si votre build dépend de fichiers binaires d'autres projets ou d'artefacts volumineux ? C'est une problématique très fréquente, qui reviendra probablement toujours. La question est donc : comment gérer cela efficacement ?

Un système de stockage comme Artifactory (qui a une extension pour Bamboo), Nexus ou Archiva peut s'avérer utile pour les artefacts générés par votre équipe ou les équipes qui vous entourent. Vous pouvez faire un pull des fichiers dont vous avez besoin dans le répertoire de build au début de votre build, comme les bibliothèques tierces dont vous faites un pull via Maven ou Gradle.

Vous pensez peut-être « Oh, j'ai juste à synchroniser mes fichiers volumineux avec le serveur de builds toutes les nuits. Ensuite, je dois les transférer sur le disque au moment du build. »

Même si un transfert de disque est bien plus rapide qu'un transfert réseau, je recommande de ne pas procéder ainsi, en particulier si les artefacts changent fréquemment. Entre chaque synchronisation nocturne, vous allez en effet créer des versions obsolètes des artefacts. Et, les développeurs ont besoin de ces fichiers pour réaliser des builds sur leurs postes de travail locaux. Pour résumer, la meilleure chose à faire reste d'intégrer le téléchargement d'artefacts au build.

2 : Utiliser des clones superficiels pour la CI

Quand un build est exécuté, votre serveur clone votre dépôt dans le répertoire de travail actuel. Comme je l'ai indiqué précédemment, lorsque Git clone un dépôt, il clone tout l'historique du dépôt par défaut. Au fil du temps, cette opération sera donc de plus en plus longue. À moins que votre système de CI utilise des clones superficiels.

Avec des clones superficiels, seul l'instantané actuel de votre dépôt peut faire l'objet d'un pull. Ils peuvent donc être très utiles pour accélérer les builds, notamment lorsque vous travaillez avec des dépôts volumineux et/ou plus anciens.

Supposons que votre build requiert l'ensemble de l'historique du dépôt par exemple lorsque vous avez un build de livraison qui ajoute un tag ou met à jour la version dans votre POM, ou encore que vous faites un merge de deux branches avec chaque build.

Les versions antérieures de Git nécessitent la présence du dépôt complet pour pusher les changements. À partir de la livraison 1.9, les changements simples apportés aux fichiers peuvent être pushés sans l'historique complet. L'historique complet est toutefois nécessaire pour les merges, car Git doit revenir en arrière et trouver l'ancêtre commun des deux branches. Ceci peut poser problème si votre build utilise le clonage superficiel. Ceci m'amène au conseil nº 3.

3 : Mettre en cache le dépôt sur les agents de build

Cette astuce accélère considérablement l'opération de clonage, et certains serveurs de CI l'appliquent par défaut.

Notez que la mise en cache du dépôt n'est bénéfique que si vous utilisez des agents qui perdurent build après build. Si vous créez et que vous détruisez les agents de build sur EC2 ou un autre fournisseur cloud à chaque exécution de build, la mise en cache du dépôt n'aura pas d'importance, car vous travaillerez avec un répertoire de build vide et vous devrez quand même faire un pull d'une copie complète du dépôt à chaque fois.

Combinés à la mise en cache du dépôt, les clones superficiels (classés par agents persistants et flexibles) peuvent s'avérer très utiles. Voici une petite matrice pour vous aider à procéder de façon stratégique.

matrice

4 : Choisissez vos déclencheurs judicieusement

Il va sans dire, ou presque, que l'exécution de la CI sur toutes vos branches actives est une bonne idée. Mais est-il judicieux d'exécuter tous les builds sur toutes les branches avec tous les commits ? Probablement pas. Voilà pourquoi.

Prenons Atlassian, par exemple. Nous avons plus de 500 développeurs, et chacun d'entre eux pushe des changements dans le dépôt plusieurs fois par jour, la plupart du temps vers les branches de fonctionnalité. Ça fait beaucoup de builds. À moins de mettre à l'échelle vos agents de build instantanément et sans limites, cela entraîne une longue attente dans la file d'attente.

L'un de nos serveurs Bamboo internes héberge 935 plans de build différents. Nous avons connecté 141 agents de build dans ce serveur et nous avons appliqué les bonnes pratiques, comme la transmission des artefacts et la parallélisation des tests pour rendre chaque build le plus performant possible. Pourtant, la génération de chaque commit provoquait un blocage.

Au lieu de simplement configurer une autre instance Bamboo avec plus de 100 agents supplémentaires, nous avons pris du recul et nous nous sommes demandé si c'était réellement nécessaire. La réponse est : non.

Nous avons constaté que pour trouver le bon équilibre entre des tests rigoureux et une préservation des ressources, il faut faire en sorte que les builds sur les branches develop soient déclenchés manuellement. C'est là que la plupart des changements ont lieu. C'est donc la meilleure occasion de faire des économies. Les développeurs sont d'avis que cette opération s'intègre naturellement à leur workflow et apprécient le contrôle et la flexibilité supplémentaires qu'elle leur procure.

Pour les branches stratégiques (comme master et les branches de livraison stables), les builds sont déclenchés automatiquement en interrogeant le dépôt sur d'éventuels changements. Comme nous utilisons des branches develop pour tous nos projets en cours, les seuls commits transmis à la branche master correspondent (en théorie) au merge de branches develop. Et, voici les lignes de code à partir desquelles nous réalisons la livraison et les branches develop. Il est donc très important que nous obtenions les résultats des tests en temps opportun lors de chaque commit.

5 : Privilégier le hooking au polling

Une autre possibilité consiste à arrêter le polling et à faire en sorte que le dépôt appelle votre serveur de CI lorsqu'un changement est pushé et doit être généré. En règle générale, on utilise un hook dans le dépôt.

Cette méthode peut être utilisée quel que soit l'outil. En l'occurrence, nous avons récemment ajouté une intégration entre Bitbucket Server et Bamboo, qui évite d'avoir à effectuer cette installation supplémentaire. Lorsque Bamboo et Bitbucket Server sont connectés sur le back-end, un build basé sur le dépot déclenche Just Work™ dès l'installation. Pas de hooks ou de configurations spéciales nécessaires.

Quels que soient les outils, les déclencheurs gérés par le dépôt ont un avantage : ils disparaissent automatiquement lorsque la branche cible est inactive. En d'autres termes, vous ne perdrez pas votre temps à interroger des centaines de branches abandonnées lors des cycles de CPU de votre système de CI. Ni même à désactiver manuellement vos builds de branche. (Notez cependant que Bamboo peut facilement être configuré de sorte à ignorer les branches après X jours d'inactivité si vous préférez interroger les branches manuellement.)

Application concrète

Vous pouvez implémenter chacune des astuces que je vous ai données dans ce billet avec tous les serveurs de CI disponibles sur le marché. Mais, puisque nous sommes toujours à la recherche de bonnes pratiques faciles à appliquer, nous les avons toutes intégrées à Bamboo afin de vous faciliter la vie. Participez à la visite et découvrez tous nos goodies.

Prêt à découvrir Git ?

Essayez ce tutoriel interactif.

Démarrez maintenant