Optimisez la gestion de vos images Kubernetes avec Argo Image Updater
Sommaire
Contexte
L’un des forts enjeux de notre transition vers une philosophie DevOps est de pouvoir livrer rapidement et efficacement. Une question que vous entendrez (ou que vous avez sûrement déjà entendue) dans votre quotidien est “Comment peut-on augmenter notre fréquence de déploiement ?”
L’un des leviers qu’on peut proposer est la mise en place d’une CI / CD (Continuous Integration / Continuous Deployment). L’objectif de la CI est de construire notre livrable, vérifier sa conformité et sa qualité. Tandis que la CD va permettre de déployer ce livrable sur un ou plusieurs environnements cibles.
Ces composantes, souvent représentées par des pipelines, vont construire / tester / packager l’application pour la CI, et déployer via des scripts automatisés pour la CD. Mais depuis quelques années, avec l'émergence de l’approche GitOps, les pipelines de CD servent à notifier un changement d’état via la modification de fichier de configuration sur le référentiel Git.
Pour les déploiements sur Kubernetes avec l’approche GitOps, il existe deux outils majeurs sur le marché et récemment promus Graduated (niveau de maturité le plus haut) dans le landscape de la CNCF : ArgoCD & Flux V2. Ces deux outils, maintenant bien connus des consommateurs de Kubernetes, nous offrent la possibilité de déployer simplement via git. Pour plus d'informations sur ces outils je vous invite à lire notre billet de blog à ce sujet.
Concentrons-nous sur la suite Argo, qui dispose d’un ensemble d’outils, dont ArgoCD Image Updater sur lequel nous allons nous focaliser dans cet article.
L’outil : Argo Image Updater
ArgoCD Image Updater a pour principal objectif de de modifier la version de l’image Docker déployée sur vos clusters Kubernetes. Ce ne sera plus à vous de définir l’image à déployer, mais à Argo d’aller chercher l’image respectant la règle mise en place, mais nous reviendrons sur ces règles par la suite.
Pour utiliser cet outil, il faut d’abord installer ArgoCD. En effet,on peut le considérer comme un add-on d’ArgoCD. Comme son parent, on va installer de nouveaux controllers sur le cluster Kubernetes :
kubectl apply -n argocd -f
https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
Première interrogation : la version stable installe la version 0.12.0 de l’application. Cette version étant sortie en mars 2022, on peut se demander pourquoi la version stable date de plus d’un an (date à laquelle j’ai écrit ce billet). Est-ce de bonne augure pour la suite ?
Mais revenons à notre objectif, à savoir : utiliser l’outil pour mettre à jour nos livrables.
Argo Image Updater propose 4 stratégies pour mettre à jour nos images docker.
Cette règle s’applique via une annotation sur l’Application déployée au préalable par ArgoCD.
La première règle, et celle appliquée par défaut, est basée sur le versioning semver (https://semver.org/lang/fr/) : l’outil installera la dernière version correspondant à la contrainte définie. Par exemple, avec l’annotation ci-dessous, Argo Image Updater, installera la dernière version corrective du Nginx en 1.24.
argocd-image-updater.argoproj.io/image-list: nginx:1.24.X
A noter que cette annotation sera obligatoire pour définir les stratégies d’update. En effet, elle va définir quelle image on souhaite modifier dans nos déploiements. Cette annotation peut permettre de définir un alias qu’on utilisera dans les autres annotations :
argocd-image-updater.argoproj.io/image-list: myalias=wescale.registry/app
argocd-image-updater.argoproj.io/myalias.update-strategy: latest
Les trois autres policies seront définies avec l’annotation
argocd-image-updater.argoproj.io/myalias.update-strategy
Vous aurez le choix entre :
- latest : analyse le registry et installe la dernière version construite (date de construction et le sha256 de l’image). Attention à ne pas confondre avec le tag latest utilisé sur les images OCI (ou autres). À utiliser avec beaucoup de précautions.
- digest : installe la dernière version correspondante à un tag (exemple la dernière version de l’image sur le tag latest et le sha256 de l’image)
- name : installe la dernière version par ordre alphanumérique, cela peut être utilisé si on utilise un versionning par date.
Une fois les annotations mises en place, vous pourrez vérifier le bon fonctionnement dans le pod d’Argo Image Updater en ayant des logs similaires à :
time="2023-10-30T20:41:23Z" level=info msg="Starting image update cycle,
considering 1 annotated application(s) for update"
time="2023-10-30T20:41:28Z" level=info msg="Setting new image to
nginx:1.25.3" alias= application=sample-app-chart image_name=nginx
image_tag=1.14.2 registry=
time="2023-10-30T20:41:28Z" level=info msg="Successfully updated image
'nginx:1.14.2' to 'nginx:1.25.3', but pending spec update (dry run=false)"
alias= application=sample-app-chart image_name=nginx image_tag=1.14.2 registry=
Versionning des images OCI
Toutes ces stratégies nous amènent à se poser une question : comment versionner ses images OCI ? En effet, la façon dont vous allez versionner vos images va conditionner votre choix de stratégie.
Voici les deux règles qui, à mon sens, sont à éviter :
- Utiliser le tag latest : chaque image doit être identifiable et immutable. Si vous utilisez le tag latest, comment peut-on identifier les failles de sécurité sur une version ? Ou bien comment savoir quelle version venons-nous de tester ? De même, quelle version devons-nous installer en production ?
- Utiliser des tags par “plateforme” : pourquoi différencier les images selon les environnements ? Cela reviendrait à dire que nous ne sommes pas iso-plateforme ou bien avez-vous peut-être rajouter de la configuration spécifique selon votre plateforme (variable d’environnement par exemple) ? Vous avez la possibilité d’utiliser les mécanismes de Kubernetes (Injection de secret, variable d’environnement) pour customiser votre déploiement selon la plateforme.
Vous l’aurez compris, je pense que l’utilisation de la stratégie digest proposée par Argo Image Updater n’est pas satisfaisante.
L'utilisation ou non du système de versionnement sémantique (SemVer) dépendra de la fréquence à laquelle vous livrez votre logiciel. Si vous avez un processus de livraison rapide qui permet de déployer une version (ou plusieurs) chaque jour, il n'est pas nécessaire de gérer des versions distinctes pour vos images, vous pouvez plutôt utiliser l'identifiant SHA du commit, par exemple.
Néanmoins, le versionning semver pourra être utilisé dans le cas ou vous souhaitez tracer les déploiements sur vos différents environnements. En effet, il est toujours plus simple de parler d’une image en version 1.4.5 que d’un sha de commit. Le rollback sera également simplifié avec le semver, où l’on pourra revenir sur une version facilement identifiable.
Dans le cas où vous devez gérer plusieurs versions en parallèle, il sera alors pertinent d’utiliser le SemVer.
Et l’approche GitOps ?
On a pu voir précédemment qu’Argo modifie la version de notre image, sans aucune action de notre part et sans modification du repository Git. On a donc un écart entre notre configuration définie sur le repository Git et l’état de notre déploiement sur Kubernetes. A cet instant, sommes-nous encore dans une approche GitOps ? Chacun aura sa réponse, et son interprétation.
Pour ma part je pense que nous sommes toujours dans une approche GitOps. Certes nous avons cet écart de configuration, donc en lisant le fichier de configuration, nous ne savons pas quelle image est déployée. Néanmoins, nous savons quelle règle nous avons appliquée, et je pense que c’est le point essentiel. A chaque fois que nous déploierons cette configuration, nous aurons l’état souhaité et identique.
Néanmoins, pour pallier cette interrogation, Argo Image Updater propose d’écrire la modification de l’image dans un fichier du type .argocd-source.yaml. Ces fichiers de configuration sont utilisés par argoCD pour surcharger les configurations des repositories par défaut.
Par exemple, on peut surcharger la donnée d’une valeur HELM. Ce fichier étant lu par ArgoCD au moment du déploiement, les modifications seront prises en compte.
Dans le cadre d’Argo Image Updater, on parlera de méthode déclarative a contrario de la méthode impérative qui utilisera l’API d’ArgoCD pour mettre à jour les images.
Pour utiliser la méthode déclarative et ainsi modifier la configuration directement dans Git vous devez ajouter l’annotation ci-dessous :
argocd-image-updater.argoproj.io/write-back-method: git
On peut également spécifier sur quelle branche Argo doit pousser la modification :
argocd-image-updater.argoproj.io/git-branch: main
A ce niveau de configuration, Argo va mettre à jour l’image dans un fichier .argocd-source.yaml sur la branche main. Cette branche étant la branche de référence, ArgoCD va appliquer la nouvelle configuration et mettre à jour l’image concernée.
Cependant, nous voulons maîtriser nos changements sur nos environnements, et ne pas voir nos versions d’image modifiées de façon un peu magique par Argo Image Updater. Pour répondre à ce besoin, l’outil permet de pousser la modification sur une autre branche que celle définie par défaut en modifiant l’annotation git-branch comme suit :
argocd-image-updater.argoproj.io/git-branch: main:feat/argo-image-update
En prenant compte de cette nouvelle configuration et toujours avec notre exemple de modification de l’image nginx, Argo a créé une nouvelle branche sur notre repository s'intitulant “feat/argo-image-update” avec la modification de l’image.
A noter qu’il est possible de modifier le message de commit en éditant la configuration d’Argo Image Updater.
A cet instant, l’image n’a pas été modifiée sur notre cluster. Néanmoins, on a la possibilité de créer une merge request vers notre branche de référence et de bénéficier de tous les atouts d’une merge request (relecture par un pair, déclenchement de tests automatisés, etc..).
Et l’information importante à retenir, c’est que nous sommes notifiés qu’il existe une nouvelle image éligible à être déployée.
Conclusion
Avec Argo Image Updater, la suite Argo s’équipe d’un outil permettant d’être proactif sur la mise à jour des images sur vos conteneurs déployés dans vos clusters Kubernetes. A l’instar des outils comme Renovate ou Dependabot, cela permet de pallier, par exemple, les failles de sécurité. L’utilisation de ce type d’outil permet également de se demander comment doit-on versionner son image pour faciliter sa mise à jour.
Néanmoins, Argo ne semble pas avoir priorisé le projet, comme en témoigne le manque de documentation et d’exemples. Peu de versions sont publiées, malgré les demandes sur le projet et on peut se demander si le projet va continuer à être maintenu dans les prochains mois. A titre personnel, je l’utiliserai dans des cas simples en utilisant la stratégie SemVer sur des images souvent mises à jour. De son côté, Flux propose lui aussi son produit permettant de modifier les images déployées selon les règles définies avec Image Update.