5 Meilleures Pratiques pour du CI/CD avec GoLang

Pour les développeurs utilisant des langages établis de longue date comme Java, JavaScript ou Python, la meilleure façon d’assembler des workflow d’intégration et de livraison continues (CI/CD) avec Artifactory est assez familière. Un ensemble mature de systèmes de gestion des dépendances pour ces langages et des solutions de conteneurs comme Docker fournissent une feuille de route claire.

Mais si vous programmez vos applications en GoLang, est-il difficile de mettre en place un système CI/CD avec la même efficacité ?

Il s’avère que le processus est bien plus facile, notamment grâce aux dernières innovations de Go. Avec le support natif d’Artifactory pour GoLang, le chemin vers un CI/CD de qualité est beaucoup plus dégagé.

« Click To Tweet

Meilleures Pratiques

Chez JFrog, nous sommes de grands fans de GoLang, que nous utilisons comme langage pour plusieurs de nos solutions phares. Et nous pratiquons aussi ce que nous recommandons, en utilisant Artifactory au cœur de notre CI/CD. Voici quelques-unes des pratiques que nous pouvons recommander :

1. Utiliser des Modules Go

Contrairement à de nombreux langages de programmation établis, les premières versions de GoLang ne fournissaient pas de mécanisme commun permettant de gérer les dépendances versionnées. Au lieu de cela, l’équipe Go a encouragé d’autres personnes à développer des outils additionnels pour le contrôle de version des packages Go.

Cela a changé avec la sortie de Go 1.11 en août 2018, avec la prise en charge des modules Go. Les modules Go, qui constituent désormais la solution de gestion des dépendances native de GoLang, sont des collections de packages Go apparentés qui sont versionnés ensemble comme une seule entité. Cela permet aux développeurs de partager du code sans avoir à le télécharger de façon répétée. 

Un module Go est défini par un fichier go.mod qui se trouve dans le répertoire racine du projet et qui spécifie le nom du module ainsi que ses dépendances. La dépendance d’un module est représentée par son nom et son numéro de version.

Si vous n’avez pas encore opté pour les modules Go, vous devez suivre les étapes ci-dessous :

  1. Si des gestionnaires de packages précédents ont été utilisés, utilisez go mod init pour générer un fichier go.mod .
  2. Si des gestionnaires de packages précédents ont été utilisés, utilisez go mod tidy . Cette commande génère un fichier go.mod déjà rempli.
  3. À partir de la version 2, le nom du module doit être modifié pour ajouter le suffixe correspondant, le chemin d’importation doit être mis à jour, des outils d’analyse statique adaptés au module doivent être utilisés et les fichiers du générateur de code, tels que les fichiers .proto , doivent être mis à jour pour refléter le nouveau chemin d’importation.

Par exemple, voici un fichier go.mod pour un module Go accessible au public pour un logger structuré :

module github.com/sirupsen/logrus

require (
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/konsorten/go-windows-terminal-sequences v1.0.1
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/stretchr/objx v0.1.1 // indirect
	github.com/stretchr/testify v1.2.2
	golang.org/x/sys v0.0.0-20190422165155-953cdadca894
)

Notez que les numéros de version doivent être conformes à la convention semver (par exemple, v1.2.1 ou 1.2.1 au lieu de 20190812) comme requis par la commande go. Vous devez éviter d’utiliser des pseudo-versions comme celle présentée ci-dessus (v0.0.0-yyyymmddhhmmss-abcdefabcdef) – bien que les pseudo-versions de type « commit hash » aient été introduites pour assurer la prise en charge des modules Go dans les projets non balisés, elles ne doivent être utilisées que comme mécanisme de repli. Si les dépendances dont vous avez besoin ont des balises de version, utilisez ces balises dans votre fichier.

Vous pouvez importer ce module Go dans votre propre code, ainsi que d’autres dépendances :

import (
	("fmt"
	"io/ioutil"
	"net/http"
	"os"

// Public Go Module for logging
	log "github.com/sirupsen/logrus")

Vous pouvez alors référencer les fonctions du module dans votre code GoLang :

   // Send text to the log
   log.Printf("Hello Log!")

2. Utiliser GOPROXY pour Garantir l’Immuabilité et la Disponibilité

Dès lors que vous gérez vos dépendances GoLang en tant que modules versionnés, vous pouvez les conserver en tant qu’entités immuables en configurant un GOPROXY. De cette façon, vous pouvez toujours vous assurer de ce que contient une version spécifique d’un module, afin que vos builds soient toujours reproductibles.

Utiliserez-vous des modules Go qui sont des packages open source accessibles au public ? Ceux que vous créez et partagez avec la communauté OSS ? Les modules que vous réservez à votre équipe uniquement ? Voici comment procéder pour chacun d’eux, ou pour tous en même temps, et faire en sorte que ces modules versionnés immuables soient toujours disponibles pour vos builds.

GOLANG.ORG

L’équipe Go de Google gère un ensemble de services GOPROXY pour les modules accessibles au public. À partir de Go 1.13, le serveur de modules proxy.golang.org est automatiquement défini comme le GOPROXY par défaut lorsque Go est installé ou mis à jour. Ce service est également pris en charge par un service d’index pour découvrir les nouveaux modules (index.golang.org), et une base de données globale go.sum pour authentifier le contenu des modules (sum.golang.org).

Le site go.dev est également géré par l’équipe Go, il est la plaque tournante pour les utilisateurs Go fournissant des ressources centralisées et organisées de l’ensemble de l’écosystème Go. Une interface utilisateur conviviale vous permet d’explorer pkg.go.dev pour effectuer des recherches parmi des milliers de packages Go open source.

Registres Go Artifactory

Le partage est une bonne chose, mais vous devrez probablement limiter l’utilisation de certains modules Go que vous créez au sein de votre organisation. Avec Artifactory, vous pouvez configurer des registres Go locaux et distants, rendant ainsi des modules publics et privés également disponibles pour vos builds.

Vous pouvez relayer le service central Go en tant que registre Go distant dans Artifactory, fournissant à votre système de génération un cache local qui accélère encore plus vos builds et vous protège contre les pannes de connexion réseau. La mise en place est simple.

Artifactory Go Registry

Vous pouvez également configurer un ou plusieurs registres Go locaux pour les modules que vous devez gérer en privé au sein de votre organisation.

Lorsque vous combinez des registres locaux et distants dans un dépôt virtuel, vos builds peuvent résoudre les dépendances des modules Go provenant à la fois d’une source publique et des modules que vous créez et gérez en privé.

Vous pouvez en savoir plus sur la façon de configurer vos dépôts GOPROXY pour Artifactory grâce à cet article de blog sur comment Choisir votre GOPROXY pour les modules Go.

3. Utiliser les Topologies du Dépôt Artifactory

Lorsque vous assemblez votre application (à l’aide de go build), où les artefacts binaires générés seront-ils stockés ? Votre processus de génération peut envoyer ces résultats intermédiaires aux dépôts dans un gestionnaire de dépôts binaires tel qu’Artifactory.

Pour ces artefacts Go intermédiaires, vous utiliserez les dépôts génériques d’Artifactory. En structurant ces dépôts de manière intelligente, vous pouvez contrôler le flux de vos fichiers binaires pour le développement, les tests et la production, grâce à des dépôts distincts pour chacune de ces étapes. Pour ce faire, utilisez la fonctionnalité Topologie du dépôt personnalisé (Custom Layout) pour Artifactory avec ces dépôts génériques.

Créer une topologie personnalisée similaire à la suivante :

[org]/[name<.+>]/[module]-[arch<.+>]-[baseRev].[ext]

Lorsque vous configurez la topologie personnalisée, il convient de tester la résolution du chemin d’accès à l’artefact pour confirmer comment Artifactory générera les informations du module à partir du chemin d’accès en utilisant les définitions de la topologie.

4. Assembler une Fois et Promouvoir

Une fois vos dépôts configurés comme il se doit pour vos builds Go, vous pouvez commencer à les déplacer efficacement dans vos étapes de pipeline. 

De nombreuses procédures de développement logiciel nécessitent un nouveau build complet ou partiel à chaque transition intermédiaire de développement, de test et de production. Mais comme les développeurs continuent de modifier le code partagé, chaque nouveau build introduit de nouvelles incertitudes ; vous ne pouvez pas être certain de son contenu. Même avec des sauvegardes pour garantir des builds déterministes, les mêmes contrôles de qualité doivent être répétés à chaque étape. 

Au lieu de cela, créez vos microservices basés sur Go une fois, puis promouvez-les à l’étape suivante une fois que les critères de promotion tels que les tests ou les analyses sont remplis. Si vous prévoyez de conteneuriser votre microservice Go, le même principe s’applique : assemblez chaque image Docker une fois et promouvez-la via une série de dépôts de staging De cette façon, vous vous assurez que ce qui a été testé est exactement ce qui sera mis en production.

Build Promotion

5. Éviter les Pipelines Monolithiques

Au lieu d’un pipeline unique et monolithique pour votre application, il est préférable d’en avoir plusieurs, chacun assemblant, testant, analysant et promouvant une couche différente. Cela contribue à rendre votre processus CI/CD plus flexible, avec différentes équipes responsables de chaque couche, et favorise un système « fail fast » qui permet une réaction rapide aux erreurs.

Par exemple, le déploiement d’une application conteneurisée peut généralement être composé de cinq pipelines :

  1. Assemblez l’application Go à l’aide de l’interface de ligne de commande JFrog CLI. Ce pipeline extrait le code source ; assemble l’application avec des dépôts Artifactory pour les dépendances et les fichiers binaires de sortie ; puis teste et promeut à partir d’un dépôt dev vers un dépôt de staging dans Artifactory.
  2. Assemblez une couche de base de l’application conteneurisée, par exemple une infrastructure Docker. Des balises statiques ou dynamiques peuvent être utilisées en fonction des stratégies de risque et de mise à niveau de l’entreprise. Par exemple, si une balise dynamique telle que alpine:3.10 est utilisé comme couche de base de l’infrastructure Docker, alors toutes les mises à jour de correctifs seront incluses chaque fois que l’infrastructure Docker est générée. Ce pipeline comprendra des étapes de build, de test et de promotion.
  3. Extrayez les artefacts promus produits par les pipelines précédents et générez une application conteneurisée, qui comportera également des étapes de build, de test, d’analyse et de promotion.
  4. Assemblez un chart Helm qui pointe vers une version balisée statiquement et promue d’une application conteneurisée produite par le pipeline précédent.
  5. Déployez l’application Go conteneurisée vers Kubernetes en utilisant le chart Helm.

Artifactory agit comme votre « source de vérité » pour vos builds Go, en fournissant un GOPROXY pour les modules publics et privés, ainsi qu’en stockant les fichiers binaires compilés. L’utilisation de JFrog CLI pour assembler votre application Go aide le processus de génération à interagir avec Artifactory et à capturer les informations de build qui rendent vos builds entièrement traçables. Voici un exemple d’extrait :

// Configure Artifactory
jfrog rt c

// Configure the project’s repositories
jfrog rt go-config

// Build the project with go and resolve the project dependencies
from Artifactory.
Jfrog rt go build --build-name=my-build --build-number=1

// Publish the package we build to Artifactory.
jfrog rt gp go v1.0.0 --build-name=my-build --build-number=1

// Collect environment variables and add them to the build info.
jfrog rt bce my-build 1

// Publish the build info to Artifactory.
jfrog rt bp my-build 1

 

Pour en savoir plus, jetez un coup d’œil à notre exemple de fichiers de démonstration pour GoLang CI/CD que nous utiliserons à GopherCon.

Boldly Go

Comme vous pouvez le constater, quelques bonnes pratiques simples dans la gestion de vos applications GoLang peuvent faciliter la voie vers un CI/CD efficace. Et Artifactory, en tant que gestionnaire essentiel de votre chaîne d’approvisionnement d’artefacts logiciels, peut jouer un rôle central en aidant à intégrer ces méthodes dans votre pipeline de développement logiciel.

Des questions ? Nous serons heureux d’y répondre à Gophercon ; rejoignez-nous pour explorer les meilleurs moyens de publier vos applications Go rapidement et avec une qualité optimale. Ou vous pouvez commencer à essayer de les mettre en pratique avec une version d’essai gratuite d’Artifactory !