10 façons intelligentes d’utiliser AWS CodeBuild

AWS CodeBuild

Au sein de votre équipe, si vous cherchez à créer rapidement des pipelines CI/CD en fonction des besoins de chaque projet pour gagner du temps ? Un seul conseil : vous devez maîtriser l’outil AWS CodeBuild.

CodeBuild est un outil de CI (« Continuous Integration », « Intégration continue » en français) entièrement géré qui vous permet de compiler votre code source, d’exécuter des tests et de produire des paquets prêts à être déployés. Découvrez ses atouts et nos 10 bonnes pratiques pour optimiser son utilisation.

Qu’est-ce que l’intégration continue et quels sont ses avantages ?

L’intégration continue est un concept prisé en DevOps, elle rassemble les pratiques utilisées en génie logiciel. Parmi lesquelles nous retrouvent les grands principes :

  • Compiler et intégrer : générer des paquets pour les langages compilés (GO, RUST, C, C++, TypeScript, …) sur un système homogène qui ne diffère pas des environnements cibles.
  • Mesurer la qualité : analyser la qualité du code selon les standards et bonnes pratiques mis en place par l’entreprise.
  • Tester : vérifier le bon fonctionnement d’une façon automatique des dernières mises à jour sur votre application.
  • Déployer : mettre à jour les services de l’environnement cible.
  • Alerter : envoyer un message sur un ou plusieurs canaux dédiés concernant autant le statut de la mise à jour de l’application que sur le lancement d’événements croisés comme, par exemple, mettre à jour un service, une configuration d’un équipement réseau, un statut dans une base de données, une notification (SMS, Mail, IM, …), un rapport d’erreurs, etc. Les options sont quasi infinies !

A chaque étape d’une mise à jour, le workflow de l’intégration continue vous permettra donc de pouvoir arrêter sa propagation avant même qu’elle ne soit déployée. Pratique ! Cela évite bon nombre d’erreurs ! Même si ce n’est pas magique et que votre code pourrait encore révéler certains bugs.

L’intégration continue est le plus couramment utilisée pour tester des mises à jour applicatives. Même si au vu de ses avantages, elle permet beaucoup plus d’automatisation, tester son application est un pré-requis qui possèdent de nombreux avantages :

  • Les modifications sont testées immédiatement avant déploiement et peuvent bloquer une mise à jour si une erreur est décelée.
  • Si une erreur remonte, les équipes peuvent être rapidement alertées.
  • Les tests sont lancés de façon continue, ce qui évite les « bugs » de dernière minute.
  • Une ou plusieurs versions de l’application sont toujours disponibles en test.

Des inconvénients ? Il ne faut pas penser l’intégration continue comme un inconvénient mais comme un investissement ! Et vous découvrirez qu’avec AWS CodeBuild, cet investissement est infime !

Quels sont les atouts de CodeBuild en terme d’intégration continue ?

A la différence d’autres outils de CI comme Jenkins par exemple, AWS CodeBuild est :

  • Entièrement géré : CodeBuild élimine la nécessité de configurer, corriger, mettre à jour et gérer vos serveurs d’automatisation.
  • Utilisable à la demande : CodeBuild s’adapte à la demande selon vos besoins de génération. Vous ne payez que pour le nombre de minutes de génération que vous consommez.
  • 
Prêt à l’emploi : CodeBuild fournit des environnements de génération préconfigurés pour les langages de programmation les plus courants. Il vous suffit de pointer sur votre script de génération pour démarrer votre première génération.
  • Intégré : CodeBuild s’intègre simplement avec tous les services AWS.

Comment utiliser CodeBuild à Tigerspike ? Voici le top 10 des utilisations :

1. Paquets, ad-hoc

Ce n’est pas pour rien qu’il s’appelle CodeBuild. Son but principal est de construire.
Supposons donc que nous voulions construire un paquet .Net Core et le mettre simplement dans S3. Tout d’abord, pour configurer notre projet CodeBuild, nous devons choisir une des images CodeBuild qui supporte notre version .Net Core. Voir la liste ici.

Ensuite, nous devons configurer le fournisseur de source, CodeCommit par exemple. Enfin, il faut ajouter un buildspec.yml (le fichier de script de construction) à votre code source. Le buildspec.yml pour ce travail devrait simplement ressembler à quelque chose comme ceci :

Plutôt simple, n’est-ce pas !

D’abord, nous avons défini la version de buildspec (0.2 est recommandé), puis nous avons défini la variable d’environnement S3_BUCKET. Ensuite, dans la phase d’installation, nous spécifions le runtime que nous voulons que CodeBuild initialise. Et heureusement, notre image et notre runtime sont livrés avec zip et AWS CLI installés, donc nous n’avons pas besoin d’exécuter d’autres commandes d’installation.

Dans la phase de construction, nous allons simplement dans le dossier du code source, restaurons .Net, construisons puis publions. Après la construction, nous allons dans le dossier de sortie, nous compressons les fichiers (au format zip) et nous les téléchargeons sur S3.

Comme vous pouvez l’imaginer, ce projet CodeBuild aura besoin d’un rôle IAM avec les bonnes permissions pour extraire du code de CodeCommit et mettre des objets dans S3.

2. Paquets, la partie de CodePipeline

Supposons le même scénario que précédemment. Nous voulons construire un paquet .Net Core mais au lieu de le télécharger vers S3, nous voulons passer les artefacts (tout ce qui a été généré par le CodeBuild) à l’action suivante, ou Stage, dans CodePipeline. Notre buildspec.yml ressemblera à ceci :

Vous avez peut-être remarqué que le buildspec ci-dessus ressemble beaucoup au précédent, sauf qu’il n’y a pas d’étape post build, ni de variables d’environnement déclarant le bucket S3. Au lieu de cela, CodePipeline transmet le code à CodeBuild, et nous déclarons quels artefacts nous voulons renvoyer à CodePipeline lorsque le travail est terminé.

Ce projet CodeBuild a seulement besoin d’un rôle IAM avec des permissions pour interagir avec CodePipeline.

3. Builds, docker

Pour cet exemple, nous allons supposer un scénario différent : nous voulons construire une image Docker et l’enregistrer dans Amazon Elastic Container Registry « ECR ». Vous pouvez ensuite utiliser ces images pour déployer des conteneurs sur AWS Elastic Container Service manuellement ou via CodePipeline. En supposant que nous avons déjà un Dockerfile dans notre dépôt, notre buildspec.yml devrait ressembler à ceci :

Notez que vous devez activer le Mode Privilégié dans les configurations de votre CodeBuild pour pouvoir l’utiliser pour construire des images Docker.

Dans ce scénario, nous avons défini notre variable d’environnement ECR_REPO qui est le référentiel ECR avec lequel nous voulons enregistrer nos images. Après cela, nous spécifions le runtime docker 18 dans la phase d’installation puis nous entrons dans les étapes de construction.

Avez-vous remarqué que nous avons marqué notre image avec la variable CODEBUILD_SOURCE_VERSION ? C’est l’une des nombreuses variables disponibles par défaut dans votre environnement de construction (https://docs.aws.amazon.com/fr_fr/codebuild/latest/userguide/build-env-ref-env-vars.html).

Pour ce projet CodeBuild, assurez-vous qu’il dispose d’un rôle IAM avec des autorisations pour s’authentifier et télécharger des images vers ECR, et interagir avec votre fournisseur de source.

4. Tests unitaires

Supposons que nous construisons un paquet Node.js en utilisant npm, mais avant de construire et de publier les artefacts, nous voulons exécuter des tests unitaires. Voici à quoi devrait ressembler notre buildspec.yml :

CodeBuild va exécuter les tests dans votre code et si les tests échouent, CodeBuild s’arrêtera à cette étape. Il ne continuera pas. Mais s’il a réussi, il passera les artefacts de construction à la prochaine action ou étape dans CodePipeline, comme dans l’exemple 2 précédemment.

Ce projet CodeBuild a seulement besoin de permissions pour interagir avec CodePipeline.
Conseil : pensez à configurer les notifications de construction en utilisant CloudWatch et SNS avec cette tâche si vous voulez être notifié en cas de succès ou d’échec.

5. Tests d’automatisation

Pour les tests d’automatisation, nos équipes préfèrent maintenir les scripts de tests d’automatisation dans des référentiels distincts de ceux de leurs applications. Nos scripts de test sont écrits en Node.js, ils exécutent des tests d’automatisation et écrivent des rapports dans un dossier de rapports local. Ensuite, nous voulons télécharger ces rapports vers S3 et notifier l’équipe via SNS.

Bien sûr, nous ne voulons pas coder en dur des données secrètes ou tout autre information sensible dans nos scripts. Nous allons les stocker au format json dans AWS Secrets Manager et les récupérer avant de lancer les tests dans des variables d’environnement que nos scripts peuvent trouver.

Ce travail automatisé permet de gagner un temps considérable. Voici un exemple simplifié d’un buildspec.yml pour ce travail :

Dans ce buildspec, nos variables d’environnement contiennent à la fois des variables en texte brut et une référence à une valeur secrète stockée dans AWS Secrets Manager. Pour plus d’informations sur la manière de référencer des variables dans un fichier buildspec, voir ici.

Dans la phase d’installation, nous spécifions la version de Node.js que nous voulons que CodeBuild exécute. Dans la phase pre build, nous obtenons l’horodatage afin de pouvoir l’utiliser pour nommer notre dossier de rapports compressés. Dans la phase de construction, nous installons les dépendances puis exécutons les tests. Après la construction, nous compressons les rapports, les téléchargeons vers S3 et en informons l’équipe par un message SNS. C’est un processus très simple en fait.

Pour ce projet CodeBuild, vous aurez besoin d’un rôle IAM qui a les permissions de récupérer des secrets à partir de Secrets Manager, de mettre des objets dans S3 et de publier sur SNS.

6. Migrations de bases de données

Pendant le développement de nouvelles applications, les ingénieurs logiciels ont souvent besoin de migrer ou de mettre à jour les schémas et les tables des bases de données. C’est une tâche souvent oubliée dans les pipelines CI/CD, mais les principes DevOps et les meilleures pratiques doivent être appliqués sur toutes les pièces du puzzle. C’est l’une des tâches critiques !

Supposons donc que nous ayons un build .Net Core qui s’exécute dans le cadre d’un CodePipeline, comme dans l’exemple 2 ci-dessus. Cependant, après la construction, nous voulons également que CodeBuild génère le script de migration SQL, se connecte à la base de données et exécute le script. Et pour faire cela, nous aurons besoin de 2 outils utiles :
– Jq : un parseur json (pour analyser les détails de connexion à la base de données à partir de json) (https://stedolan.github.io/jq/)
– MySQL client (pour se connecter à notre base de données MySQL, par exemple Aurora) (https://dev.mysql.com/doc/refman/8.0/en/mysql.html).
Voici à quoi devrait ressembler le fichier buildspec.yml :

Dans le buildspec ci-dessus, nous avons demandé à CodeBuild d’exécuter .Net Core 3.1 et d’installer jq et le client MySQL.

Une fois installé, nous récupérons nos valeurs secrètes concernant la connexion à la base de données depuis AWS Secrets Manager vers nos variables d’environnement. Ces valeurs sont contenues dans les détails de l’objet au format json récupéré depuis AWS Secret et doivent correspondre à la connexion souhaitée. Après cela, nous allons restaurer, construire et publier .Net puis générer le script de migration SQL.

Après la construction, nous nous connecterons à la base de données en utilisant des variables d’environnements générées et nous transmettrons le script de migration à la base de données pour qu’il soit exécuté. Une fois terminé, comme précédemment, nous transmettrons les artefacts de construction à CodePipeline.

Ce projet CodeBuild aura besoin d’un rôle IAM qui a les permissions d’interagir avec Secrets Manager et CodePipeline. En outre, ce projet CodeBuild devra être en mesure de se connecter à l’instance de la base de données, par exemple, se connecter dans le VPC.

7. Opérations de base de données

Comme dans l’exemple précédent, nous voulons effectuer des opérations de base de données quelque part dans notre pipeline CI/CD. Disons par exemple que nous avons une instance de base de données de développement, mais que nous voulons que notre grande équipe d’ingénieurs la partage. Nous ne voulons pas que chacun se connecte à la base de données pour créer de nouveaux schémas (bases de données) et oublie de les supprimer lorsque son travail est terminé. Nous voulons automatiser ce processus.

Nous voulons qu’un nouveau schéma soit créé pour chaque branche de fonctionnalité et qu’il soit supprimé lorsque la branche est fusionnée.

Ce n’est pas compliqué, cela permet de gagner du temps et de garantir des nettoyages appropriés. Nous l’avons fait pour l’un de nos grands projets dont l’équipe était répartie sur plusieurs bureaux et c’était formidable. Tout ce que nous avions à faire était de configurer notre contrôle de version pour déclencher un travail lorsqu’une nouvelle branche est créée ou lorsqu’une branche est fusionnée. Et lors du déclenchement, nous transmettons le nom de la branche et « create » ou « drop » comme variables d’environnement. Tout contrôle de version moderne avec des capacités de pipeline peut déclencher CodeBuild via AWS CLI.

Pour référence, voici à quoi ressemble la commande CLI de déclenchement, y compris le nom de la branche et l’action requise, si nous déclenchons à partir de Bitbucket :

Et voici à quoi devrait ressembler le fichier buildspec.yml :

Comme dans l’exemple précédent, nous récupérons les valeurs secrètes de notre connexion à la base de données à partir du gestionnaire de secrets via les variables d’environnement. Nous définissons la commande SQL que nous voulons exécuter en fonction de la variable d’environnement $ACTION entrante, à savoir créer ou supprimer. Nous incluons également le nom $BRANCH dans la commande pour faire correspondre le nom du schéma. Une fois la commande SQL définie, nous nous connectons à la base de données et exécutons la commande.

Comme nous l’avons mentionné, cette tâche peut être exécutée pour créer ou supprimer des schémas. Le nom du schéma correspondra au nom de la branche de la fonctionnalité. Veillez donc à ce que le nom de la branche soit limité aux caractères pris en charge par votre moteur de base de données. Sinon, vous pouvez ajouter une logique dans votre script pour vérifier le nom de la branche et convertir les caractères non supportés.

Ce projet CodeBuild n’a besoin que de permissions pour récupérer des secrets à partir de Secrets Manager, et d’un accès réseau à la base de données, par exemple via le VPC.

8. CloudFormation

Nous utilisons souvent l’intégration de CodePipeline avec CloudFormation pour déployer ou mettre à jour nos piles. Cela peut s’avérer délicat si vos piles CloudFormation sont organisées en piles imbriquées. Ce que vous feriez habituellement pour déployer manuellement est d’utiliser AWS CLI pour empaqueter les modèles en un seul que vous pouvez déployer. N’ayez crainte, il est facile de reproduire cette opération dans un pipeline CI/CD. Voici un exemple de buildspec.yml :

Très simple, dans le buildspec ci-dessus, nous avons défini le seau et la région où nous voulons télécharger les modèles imbriqués afin de pouvoir empaqueter CloudFormation.

Ensuite, nous avons exécuté la commande package. Comme vous pouvez le constater, cette tâche CodeBuild transmet le modèle packaged.yml ainsi que les fichiers de paramètres de type json comme artefacts à l’action de déploiement suivante dans CodePipeline. Vous n’êtes pas obligé d’utiliser des paramètres ou des fichiers de paramètres avec CloudFormation, mais c’est une bonne pratique, alors faites-le quand cela a du sens.

Ce projet CodeBuild aura besoin de permissions pour écrire dans le seau S3 spécifié (pour CloudFormation) ainsi que de permissions pour interagir avec CodePipeline.

9. Balisage du dépôt de code source

Dans certains flux de travail, nous sommes tenus de marquer le commit, dans le contrôle de la source, que nous venons de déployer avec succès dans un environnement. Par exemple, après un déploiement réussi en production, nous voulons étiqueter le commit déployé dans le contrôle de source avec une étiquette prod.

Pour ce faire, CodeBuild aura besoin d’une clé SSH Git, que nous stockerons dans AWS Secrets Manager, et que nous passerons dans les variables d’environnement.
Voici à quoi devrait ressembler notre buildspec.yml :

Ci-dessus, nous avons défini nos variables d’environnement, à savoir le nom du dépôt GitHub et une référence à la clé SSH Git stockée dans AWS Secrets Manager. CodeBuild va alors écrire la clé SSH dans le dossier SSH, se connecter à GitHub, puis cloner le dépôt. Une fois cloné, nous supprimerons le tag s’il existe déjà, nous marquerons le commit que nous avons déployé puis nous le pousserons vers GitHub. Dans ce scénario, nous avons utilisé la variable d’environnement disponible CODEBUILD_SOURCE_VERSION qui est l’ID du commit transmis par CodePipeline comme expliqué ici. Si vous n’avez pas l’ID du commit dans les variables disponibles, vous pouvez le passer avec votre build dans un fichier.

Ce projet CodeBuild a besoin de permissions pour récupérer les secrets du Secrets Manager et pour interagir avec CodePipeline.

10. Marquage de déploiement

Une des bonnes pratiques à faire après les déploiements est de marquer la ligne de temps de votre système de surveillance avec l’heure et la version du déploiement. Il s’agit d’un enregistrement qui vous aidera à voir les changements dans les performances et l’utilisation de votre application et à les corréler avec les déploiements. NewRelic, par exemple, vous permet d’enregistrer les déploiements via l’API REST. Vous trouverez ci-dessous un exemple de buildspec.yml pour ce travail :

Cette tâche envoie simplement une requête POST à NewRelic en utilisant l’APP ID et la clé API récupérés dans Secrets Manager. La requête POST comprend les paramètres requis, y compris une révision et une description.

Nous avons utilisé CODEBUILD_SOURCE_VERSION ou l’ID de commit comme révision dans cet exemple.

Encore une fois, ce projet CodeBuild a besoin de permissions pour récupérer les secrets du Secrets Manager et pour interagir avec CodePipeline.

Conclusion

Nous sommes tous d’accord pour dire que chaque projet a ses propres exigences et que chaque CI/CD est unique. Mais lorsque vous disposez d’un outil aussi performant et facile à utiliser, autant l’utiliser de manière intelligente. Protégez vos secrets, automatisez les tâches, réduisez les risques d’erreur et économisez du temps et des efforts.

Source : https://malsouli.medium.com/10-smart-ways-to-use-aws-codebuild-22a8ee0d9302