Comment orchestrer les workflows GitHub Actions pilotés par l’immuabilité des images
L’adoption de GitHub Actions a augmenté ces dernières années. Selon une enquête de The Software House pour l’état du frontend, GitHub Actions occupe le devant de la scène dans les outils CI/CD, avec plus de 56 % en 2022 contre 35 % en 2020. Cela montre que davantage de développeurs sont passés à GitHub Actions comme outil CI/CD à leur époque. aujourd’hui.
Guidés par l’architecture de pipeline en libre-service DevOps, nous avons exploré la structure du projet Terraform et ses modules réutilisables dans notre article précédent. Cet article explique comment orchestrer les pipelines d’applications avec GitHub Actions. Nous allons nous concentrer sur le rectangle en surbrillance rouge dans le diagramme ci-dessous.
Flux de travail réutilisable des actions GitHub
Dans la pratique centrée sur le libre-service de DevOps, la réutilisabilité est essentielle. Tout comme les modules Terraform réutilisables, nous pouvons avoir des flux de travail GitHub Actions réutilisables dans nos pipelines CI/CD d’application.
Du point de vue avec/sans état, les workflows réutilisables sont sans état. Les flux de travail appelant de nombreuses applications différentes peuvent appeler un flux de travail réutilisable.
J’ai publié il y a quelques mois un article intitulé A Deep Dive into GitHub Actions’ Reusable Workflows, dans lequel j’ai exploré les étapes détaillées pour rendre un workflow GitHub Actions réutilisable, comment appeler un workflow réutilisable et comment transmettre des paramètres d’entrée et des secrets à le workflow réutilisable. Un exemple de code a été partagé dans cet article, et il est répertorié au bas de cet article. Je vous recommande fortement de consulter cet article si vous êtes nouveau dans le flux de travail réutilisable de GitHub Actions.
Une fois que vous aurez commencé à utiliser des flux de travail réutilisables dans vos projets, vous ne regarderez plus en arrière, car les flux de travail réutilisables vous font gagner beaucoup de temps et d’efforts pour déployer les flux de travail CI/CD de vos applications et éliminer les problèmes de maintenance.
L’immuabilité des images de conteneurs fait référence à la création et à l’utilisation d’images de conteneurs qui ne peuvent pas être modifiées après leur création. Une fois qu’une image est construite et poussée dans un registre, elle ne doit pas être modifiée. Au lieu de cela, une nouvelle image doit être créée avec les modifications souhaitées et déployée.
Le principal avantage de l’immuabilité de l’image de conteneur est sa prévisibilité. Lorsque l’immuabilité des images est appliquée, vous pouvez être sûr que votre application se comporte comme prévu dans des environnements tels que la mise en scène et la production. L’immuabilité de l’image vous offre également la tranquillité d’esprit de revenir à une balise d’image précédente en cas d’erreur, car vous savez que la balise d’image précédente est immuable et n’a pas été altérée par les versions après sa publication. Dans l’ensemble, l’immuabilité contribue à assurer la cohérence, la sécurité et la reproductibilité des images de conteneurs.
Le déclenchement de CI avant chaque CD pour chaque environnement ne garantit pas l’immuabilité de l’image. Pourquoi? Chaque CI peut produire une image différente même si vous n’avez pas modifié votre code source. Si vous avez des mises à niveau de dépendance et une fusion automatique automatisées par des outils tels que GitHub dependabot, votre code source varie en fonction du moment où vos dernières mises à niveau de dépendance ont eu lieu. Pour cette raison, l’image construite il y a une semaine et l’image construite aujourd’hui pourraient être deux images différentes malgré l’absence de modifications manuelles du code entre les deux.
Pour renforcer l’immuabilité de l’image, nous devons séparer le CI du CD, en les transformant en deux workflows isolés. CI construit et pousse l’image vers ECR, et CD doit être suffisamment intelligent pour savoir exactement quelle balise d’image utiliser pour extraire cette image immuable. Les équipes qui avaient l’habitude d’utiliser l’horodatage de la date ou Git SHA dans le cadre de la balise d’image sont désormais confrontées à un dilemme : comment savoir quelle balise d’image utiliser lorsque vous déclenchez le CD ? Vous pouvez essayer de tracer votre journal de débogage de flux de travail CI pour déterminer quelle balise d’image a été publiée sur ECR, mais cela va à l’encontre de l’objectif de l’automatisation. Tout effort manuel dans ce flux n’est pas une solution souhaitable.
En fin de compte, cela se résume à : comment vous assurez-vous que votre balise d’image est immuable ?
Continuez à lire pour le découvrir.
Supposons que vous développiez une application Spring Boot en utilisant Maven comme outil de construction, et que votre application sera déployée dans trois environnements : développement, staging et prod. L’automatisation de Maven Release est la clé pour maintenir l’immuabilité de l’image du conteneur. Examinons de plus près le fonctionnement de Maven Release.
Le diagramme ci-dessus devrait être assez explicite. Maven Release automatise la publication des balises et fait passer la version pom à la prochaine version de développement. Si vous exprimez le flux de publication Maven ci-dessus dans un flux de travail réutilisable GitHub Actions, vous aurez l’exemple de flux de travail de publication suivant.
Les étapes clés du flux de travail ci-dessus sont :
- Ligne 57–62 : c’est là que la magie opère par Maven Release, lancez simplement
mvn -B release:prepare release:perform
, Maven Release supprime votre instantané de votre version pom, balise la version de publication, publie votre artefact dans le registre d’artefacts tel que les packages GitHub et passe à la version de développement suivante. Cette seule commande déclenche toutes les actions. Remarquez la ligne 62, une logique de nouvelle tentative a été ajoutée pour minimiser la charge de pointe GitHub envoyant une erreur de serveur interne 500. Il s’agit d’une solution de contournement recommandée par le support technique de GitHub lorsque j’ai déjà rencontré une telle erreur. - Lignes 52 à 55 : cette étape crée un utilisateur git pour pousser vers la publication automatisée de l’instantané pom de GitHub, la mise à jour de la prochaine version, etc.
- Ligne 64–66 : en cas d’échec lors de Maven Release, l’étape annulera Maven Release par la commande
mvn -B release:rollback
.
Gardez à l’esprit que la version de Maven Release est immuable. Alors, comment Maven Release est-il lié à l’immuabilité de l’image du conteneur ? Vous l’avez deviné – publiez le numéro de version en tant que balise d’image de conteneur ! Comment ça marche exactement ? Continuons l’exploration.
Supposons que vous ayez développé/compilé une liste de workflows réutilisables sans état pour votre application pour CI, CD et release. Comment reliez-vous ces flux de travail afin qu’ils puissent être orchestrés pour composer ce chef-d’œuvre pour votre CI/CD ?
Commençons par ce diagramme d’orchestration de flux de travail ci-dessous :
Pouvez-vous entendre qu’il y a une symphonie en cours? 🙂 Reprenons les étapes :
- Lorsque vous lancez une nouvelle demande d’extraction pendant le développement actif, elle déclenche automatiquement votre flux de travail CI.
- Le flux de travail CI effectue la génération, le test, la création d’image Docker et la transmission à votre registre de conteneurs, tel qu’ECR, et il termine également l’analyse de l’image pour la vulnérabilité. Veuillez noter que la balise image ici utilise la version du projet définie dans votre application pom.
- Après plusieurs séries d’examens de PR et de corrections de code, votre PR a finalement été approuvé et vous êtes prêt à fusionner votre PR avec votre branche par défaut. Lors de la fusion PR, il déclenche automatiquement le flux de travail de votre CD.
- Le flux de travail du CD extrait votre image docker du registre de conteneurs et la déploie vers votre destination prédéfinie, telle que ECS.
- Après de nombreuses itérations de développement, votre application est prête à être promue dans un environnement intermédiaire. Vous créez une branche de publication pour une version de release candidate (RC), qui déclenche le workflow de publication pour automatiser Maven Release.
- L’artefact RC est publié dans les packages GitHub ou dans tout autre registre d’artefacts de votre choix avec une configuration appropriée en place.
- Une fois Maven Release réussie, vous devez déclencher le flux de travail du CD pour déployer la version RC sur Dev via le déclencheur manuel, où vous pouvez sélectionner l’environnement de développement et la balise (pas la branche principale). Notez que vous devez sélectionner la balise dans la liste déroulante, qui vient d’être publiée par Maven Release à l’étape 6.
- Le CD, à son tour, déclenche le flux de travail CI car vous devez maintenant créer la nouvelle image de la version RC.
- Le flux de travail CI effectue la construction, le test, la construction de l’image docker, la transmission à ECR et analyse les images à la recherche de vulnérabilités.
- Le CD extrait l’image de la version RC d’ECR et la déploie sur Dev.
- Lorsque vous déployez l’image de la version RC sur Staging, vous déclenchez le CD via le déclencheur manuel en sélectionnant Staging env et la balise RC (pas la branche principale).
- Le CD extrait l’image de la version RC d’ECR et la déploie sur Staging. Les étapes 5 à 12 peuvent répéter plusieurs cycles en fonction de l’état de développement de votre application, des corrections de bogues, etc., jusqu’à ce que vous soyez enfin prêt à publier la version finale (sans RC). Suivez les étapes 5 à 12 pour publier votre version finale et déployez-la sur Dev et Staging.
- Lorsque vous déployez l’image de version de version sur Prod, vous déclenchez le CD via le déclencheur manuel en sélectionnant Prod env et la balise de version finale (pas la branche principale). Je suggère de configurer la règle de protection du déploiement GitHub pour garantir que la chaîne d’approbation appropriée a lieu avant que le déploiement Prod ne puisse être réellement déclenché.
- Le CD extrait l’image de la version finale d’ECR et la déploie sur Prod.
Quelques observations clés :
Le flux de travail CI n’est appelé que deux fois dans tout ce cycle de vie. Le premier provient de la création/fusion des relations publiques pendant la phase de développement actif. Le deuxième appel provient du flux de travail CD après la version Maven, qui a supprimé l’instantané, le flux de travail CI est déclenché pour créer l’image de la version RC ou l’image de la version finale, qui est déployée dans tous les environnements.
Vous pouvez avoir plusieurs itérations de push d’image d’instantané et de push de version RC, mais chaque version Maven incrémentera leur numérotation pour la version RC ou la version de version, rendant chacune de ces versions de version immuable. Avec la version Maven, il est garanti que vous ne pouvez pas publier deux fois la même version (qu’il s’agisse d’une version RC ou d’une version publiée) dans votre registre d’artefacts. Sinon, vous rencontrerez une erreur 409.
Au cours de plusieurs cycles de déploiement de mise en scène, vous ne devez pas continuer à augmenter le numéro de version du correctif dans votre version sémantique (SemVer, major.minor.patch). La version release candidate (RC) est introduite pour vos déploiements Staging pour autant de cycles que nécessaire sans impact sur votre SemVer lorsque votre application est publiée sur Prod.
Prenons un angle différent et regardons comment ces versions RC sont gérées entre la branche principale et vos branches de publication. J’espère que cela vous donnera une meilleure idée de la façon dont Maven Releases est liée à l’immuabilité de l’image du conteneur.
Comme vous pouvez le voir sur le diagramme d’orchestration ci-dessus, trois workflows sont impliqués : ci.yml
, cd.yml
et release.yml
. Ces workflows sont tous des workflows appelants, ce qui appelle des workflows réutilisables. Voyons à quoi ressemblent les flux de travail des appelants :
ci.yml
est simple sans astuces. Il s’agit d’un flux de travail simple appelant un flux de travail réutilisable, et il est déclenché en créant un PR ou en poussant du code dans le PR.
cd.yml
est un peu plus impliqué. Voir les raisons suivantes :
- Il est déclenché soit par une fusion PR (en développement), soit par un déclencheur manuel.
- S’il s’agit d’un environnement de développement ou d’une fusion PR, cela déclenche également le
build-and-test
travail, ce que fait le flux de travail CI. Pourquoi avons-nous besoin de cette condition et de ce travail dans le flux de production de CD ? L’environnement de développement sera constamment mis à jour avec la dernière image, qui aurait le SNAPSHOT dans la version pom. Si nous n’effectuons pas lebuild-and-test
étape avant ladeploy-to-ecs
étape, il n’y a aucune garantie que l’image du développeur A ne sera pas écrasée par l’image du développeur B, car ils partagent tous les deux la même balise d’image, la version SNAPSHOT. - Si c’est pour des environnements autres que dev, le
build-and-test
le travail est ignoré à cause de cette instruction conditionnelle à la ligne 22 (voir ci-dessous le code). La ligne 34 assure celadeploy-to-ecs
Le travail est exécuté uniquement lorsque PR est fusionné dans dev, ou pour d’autres environnements via un déclencheur manuel, et PR n’est pas déclenché par dependabot. C’est là que l’implémentation de l’immuabilité de l’image est en action. Examinez de plus près le diagramme d’orchestration ci-dessus. La mise en scène et la production déclenchent uniquement le flux de travail du CD, qui extrait l’image de la version RC ou de la version d’ECR et la déploie.
Comment le workflow de CD sait-il quel numéro de version utiliser comme balise d’image ? Regardez dans nos flux de travail réutilisables CI et CD, où PROJECT_VERSION
est distingué du code extrait (code de branche pour Dev env et code de balise pour Staging et Prod) en exécutant mvn help:evaluate
pour extraire sa version de projet, puis la configurer en tant que variable d’environnement pour l’envoi et l’extraction de la balise d’image.
- name: Set project version as environment variable
run: echo "PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
release.yml
est à nouveau très simple, déclenché soit par un déclencheur manuel, soit par la création d’une branche avec une convention de nommage commençant par release/
. Après cela, effectuez un simple appel au workflow réutilisable. Voir l’exemple ci-dessous :
Ceci conclut notre orchestration de flux de travail basée sur l’immuabilité des images de conteneurs. J’aimerais entendre des commentaires pour améliorer cette orchestration. Si vous avez une manière différente de gérer l’orchestration du flux de travail avec l’immuabilité des images, laissez un commentaire pour nos lecteurs et moi.
Tous les exemples de code peuvent être trouvés dans mes référentiels GitHub :
Cet article s’est concentré sur l’orchestration du flux de travail GitHub Actions pilotée par l’immuabilité de l’image du conteneur. Nous avons exploré plusieurs sujets tels que les workflows réutilisables, l’immuabilité des images, les avantages et les défis de l’immuabilité des images dans les pipelines, l’automatisation des versions Maven et la manière de lier tous les workflows dans le cycle de vie du CI/CD/release d’une application. J’espère que vous avez trouvé cet article utile.
Bon codage !