Aller au contenu

Automatisez vos mises à jour avec Updatecli

·6 mins·
Gitops Update
Anthony Benguerfi
Auteur
Anthony Benguerfi
En cours de rédaction 🚧

Contexte
#

Comment mettre à jour constamment nos applications en production ? 🤔

C’est une problématique à laquelle on fait très souvent face dans le domaine de l’infrastructure, et qui a tendance à revenir en permanence.

Les besoins évoluent, les stacks se complexifient, et on peut rapidement tomber dans le piège de ne pas assez rationaliser les applications et d’en déployer toujours plus. C’est encore plus vrai dans une infrastructure moderne avec Kubernetes et tous les outils qui gravitent autour, comme Argo CD, Helm, etc. qui facilitent grandement le déploiement d’une application. Facile alors de négliger le coût de maintenance : déployer un nouvel outil tout beau tout neuf, c’est cool… mais derrière, il faut le maintenir.

Ce constat peut aussi venir d’une forte croissance, où les équipes n’ont simplement pas eu le temps de “scaler” au même rythme que le nombre de services déployés.

Face à ça, on peut envisager plusieurs solutions :

  • La plus basique serait de mettre à jour manuellement les applications. Quand on n’a que quelques services à maintenir, ça peut faire l’affaire. Mais au bout d’un moment, on se rend vite compte que ce n’est pas viable sur le long terme : c’est chronophage, fastidieux, et plus le temps passe, plus il y a des risques d’être négligent sur ce sujet.
    Résultat : la dette technique grossit, on se retrouve avec des applications en production qui traînent plusieurs failles de sécurité exploitables, sans parler du retard accumulé sur les nouvelles fonctionnalités. Pour certaines, parfois plusieurs versions majeures de retard et plus personne n’ose y toucher par peur de tout casser, l’application finit sous le tapis, un cas classique… 🫣

  • L’autre solution évidente serait d’automatiser ces mises à jour.
    Très bien, mais comment ? On peut imaginer un script Bash ou Python, mais est-ce que ça couvrira tous les cas d’usage et tous les contextes sans se transformer en usine à gaz maintenable uniquement par la personne qui l’a écrit ?

L’automatisation est sans aucun doute la bonne réponse face à cette problématique, mais il faut l’aborder correctement et standardiser le processus de mise à jour.

Et ça tombe bien, il existe un outil qui fait exactement ça : Updatecli.

Présentation d’Updatecli
#

Updatecli est un gestionnaire de mises à jour, Open-source, écrit en Go.
C’est un outil en ligne de commande qui exécute une pipeline de mise à jour, configurée dans un fichier YAML.

Cette pipeline se décompose en plusieurs étapes :

  • Source : décrit ce qu’on veut récupérer comme information et où.
  • Condition : définit les conditions qui doivent être remplies pour déclencher l’étape “target”.
  • Target : définit le fichier à modifier, que ce soit en local ou sur un repo Git, en utilisant les informations transmises par la source.
  • Action : définit quoi faire après les modifications effectuées par l’étape “target”. Par exemple, effectuer une MergeRequest.

À chaque étape d’une pipeline Updatecli, différents plugins peuvent être utilisés : dockerimage, yaml, shell, argocd, kubernetes, et bien d’autres encore.
La liste complète est disponible dans la documentation officielle Updatecli : https://www.updatecli.io/docs/prologue/introduction/

C’est l’une des grandes forces d’Updatecli : sa flexibilité et sa polyvalence.
En fonction du contexte et du cas d’usage, il suffit de choisir le bon plugin, de lui passer quelques paramètres, et le tour est joué.

Exemple simple avec Nginx
#

Maintenant que les bases sont posées, passons à un cas concret.
Prenons un exemple simple avec un fichier YAML qui référence une image Nginx, mais cela pourrait tout aussi bien être un Dockerfile, un Helm Chart, etc.

---
container:
  image: docker.io/nginx
  tag: 1.29.4

Pour maintenir automatiquement à jour l’image Nginx utilisée, on va utiliser ce manifest Updatecli :

# manifest.yaml
name: QuickStart example

# Defines how to get "source" information
sources:
  nginxVersion:
    name: Get the latest nginx version
    kind: dockerimage
    spec:
      image: nginx
      versionfilter:
        kind: semver

# Defines "targets" which need to be updated if different than "source" information.
targets:
  dataFile:
    name: Bump Nginx Docker Image Tag
    kind: yaml
    spec:
      key: container.tag
      file: data.yaml

En appliquant ce manifest avec Updatecli, il va récupérer la dernière version disponible sur DockerHub et mettre à jour le tag dans le fichier YAML.

💡 Pour ceux qui se demandent pourquoi ne pas utiliser simplement le tag latest, je vous invite à lire cet article qui résume bien pourquoi c’est une mauvaise pratique en production : https://mifergo.medium.com/why-you-should-stop-using-the-latest-tag-in-docker-167c641e6da2

Cet exemple reste volontairement basique afin d’illustrer le fonctionnement d’Updatecli.
Là où l’outil prend tout son sens, c’est dans une infrastructure qui adopte une approche GitOps.

Intégration GitOps
#

Pour ceux qui sont peu familiarisé avec ça, le “GitOps” est une approche où Git devient la source de vérité pour l’état souhaité de l’infrastructure et des applications.
Un outil de CD (Continuous Delivery), par exemple ArgoCD, compare l’état réel d’une application dans un cluster Kubernetes avec ce qui est défini dans Git.
S’il y a une différence, ArgoCD alerte (OutOfSync) ou synchronise automatiquement le cluster pour que ça corresponde à ce qui est défini dans Git.

Concrètement, où intervient Updatecli dans ce flux de déploiement ? Dans la CI GitLab.
Lorsqu’une action est détectée sur le repository (par exemple un commit), la pipeline se déclenche. Elle contient deux stages principaux :

  • argocd : ce stage applique un manifest ArgoCD qui décrit l’application à déployer sur un cluster Kubernetes. Tout est déclaratif : On décrit le repo, le chart, la targetRevision, le values à utiliser, etc.

Exemple avec le déploiement de Grafana :

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: 'demo-grafana'
  labels:
    env: dev
spec:
  project: infra
  sources:
    - repoURL: 'https://grafana.github.io/helm-charts'
      chart: grafana
      targetRevision: 10.1.4
      helm:
        valueFiles:
          - $values/grafana/values.yaml
    - repoURL: '${CI_PROJECT_URL}'
      targetRevision: main
      ref: values
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: demo-grafana
  syncPolicy:
    automated:
      prune: true
    syncOptions:
      - CreateNamespace=true
	  
  • updatecli : Ce stage applique un manifest Updatecli configuré pour maintenir à jour la version du Helm Chart de Grafana. Updatecli va gérer ici la key targetRevision du fichier ArgoCD.
# manifest.yaml
name: Demo Grafana

# Defines how to get "source" information such as Jenkins version
sources:
  latestVersion:
    name: Get the latest Grafana version
    kind: helmchart
    spec:
      url: https://grafana.github.io/helm-charts
      name: grafana

# Defines "targets" which need to be updated if different than "source" information.
targets:
  upgrade_app:
    name: Update argocd/grafana.yaml
    kind: yaml
    scmid: gitlab
    spec:
      engine: yamlpath
      file: argocd/grafana.yaml
      key: $.spec.sources[0].targetRevision    

# Open (or update) a MR when a target is modified
actions:
  default:
    title: Bump Grafana version
    kind: gitlab/mergerequest
    scmid: gitlab
    spec:
      reviewers:
        - 257

# Manage git repositories hosted on Gitlab
scms:
  gitlab:
    kind: gitlab
    spec:
      owner: "afbeng"
      url: '{{ requiredEnv "GITLAB_URL" }}'
      repository: "demo-updatecli"
      branch: '{{ requiredEnv "CI_COMMIT_BRANCH" }}'
      commitmessage:
        title: "Update Grafana to the latest version"
      username: '{{ requiredEnv "UPDATECLI_USER" }}'
      token: '{{ requiredEnv "UPDATECLI_TOKEN" }}'
      user: '{{ requiredEnv "UPDATECLI_USER" }}'
      email: '{{ requiredEnv "UPDATECLI_EMAIL" }}'

Le stage Updatecli est exécuté régulièrement via une “pipeline schedules”. Si une nouvelle version du Chart Grafana est détectée, Updatecli crée une branche, met à jour la version dans le manifest d’ArgoCD et ouvre automatiquement une Merge Request en m’ajoutant comme reviewer.

Il ne reste plus qu’à valider et merger la MR, ce qui déclenchera la CI et donc le stage “argocd” qui mettra à jour l’application avec la nouvelle version.

💡 Il est possible d’activer l’auto-merge dans l’étape actions, mais cela reste bien évidemment à manier avec précaution pour les applications de production.

Conclusion
#

Voilà pour cette première intégration simple d’Updatecli dans un contexte GitOps.

N’hésitez pas à tester Updatecli, l’outil est suffisamment flexible pour être utile dans des environnements et contextes différents.

Pour aller plus loin, il y a des features intéressantes comme l’AutoDiscovery ou les Policies par exemple, qui feront peut‑être l’objet d’un prochain article.