Contactez-nous
-
Cloud Native

Helm pour les nuls et moins nuls

Helm pour les nuls et moins nuls

Sommaire

Kubernetes est aujourd’hui un outil de gestion de conteneurs incontournable, présent chez tous les grands fournisseurs de cloud. Il existe plusieurs moyens de déployer des applications dessus, et il n’est pas évident pour un débutant de comprendre les différences entre celles-ci.

Helm est l’outil de déploiement d’applications sur Kubernetes le plus populaire, permettant de nombreuses formes de configurations et personnalisations de vos déploiements. Il est très souvent opposé à Kustomize.

Nous allons voir ensemble ce qu’est Helm, comment il fonctionne, et ce qui le rend si populaire. 

Définition et caractéristiques de Helm

Helm est un gestionnaire de paquets pour Kubernetes. Il permet d’installer, en deux commandes, une application provenant de n’importe quelle source sur votre cluster ; le seul prérequis pour cette installation est la présence du binaire “helm” sur votre poste.

Helm est le pendant de Kubernetes de yum et apt dans les mondes Redhat et Debian.

En tant que gestionnaire de paquets, Helm ne permet pas uniquement une installation rapide, il permet aussi une installation versionnée d’une application. Cet aspect est important, car il va vous permettre de savoir ce qui est déployé à un instant T sur votre cluster, ainsi que faciliter sa montée (ou descente !) de version.

Si par exemple, vous avez installé un serveur Minecraft avec Helm, et que les développeurs du package ont sorti une nouvelle version, vous pourrez facilement mettre à jour votre instance de l’application en une seule commande Helm.

Enfin, un des avantages de Helm aujourd’hui est sa standardisation : si un cluster utilise Helm, même en étant nouveau sur le projet, vous pouvez avoir une idée de ce qui tourne dessus.

Comment fonctionne Helm ?

Un cluster Kubernetes permet de déployer des applications sur un ensemble de nœuds à l’aide de d’objets simples à gérer : un objet peut représenter un volume, une instance de l’application, un service réseau permettant de communiquer avec l’application… 

Ces objets sont souvent représentés sous forme de manifestes YAML.

Les applications déployées sur Kubernetes sont généralement complexes, et auront besoin de plusieurs de ces objets pour fonctionner correctement. On aura besoin de faire fonctionner son application (avec un Deployment), lui donner des paramètres (avec des ConfigMap et/ou des Secrets), permettre son accès depuis l’intérieur du cluster (avec un Service) et/ou depuis l’extérieur (avec un Ingress)… En bref, beaucoup de manifestes à gérer pour une seule application !

Une application est composée d’une multitude de manifestes

Ces manifestes peuvent être très verbeux, détaillant chaque paramètre du composant associé. Ces paramètres peuvent être différents en fonction de ce que vous voulez, par exemple votre application consomme moins de ressources sur un cluster de développement que sur un cluster de production.

Au commencement, on gérait les manifestes manuellement : soit on devenait des pros du copier-coller, soit on faisait des scripts pour pouvoir paramétrer ses manifestes et éviter de dupliquer trop le code.

Kustomize est un des outils qui est devenu référence dans cette fonction : il permet, à partir d’un manifeste YAML, de le modifier en fonction de patchs (= des petits changements) avant de l’appliquer sur un cluster.

Helm a pris le chemin du templating: on définit nos objets sous formes de templates avec des paramètres, on inscrit des valeurs par défaut lors de la création du Chart (le package contenant l’application), puis on permet à l’utilisateur de donner ses propres paramètres lorsqu’il veut appliquer le Chart sur son cluster. Lors du déploiement, Helm va substituer les paramètres par les valeurs fournies, vous donnant les manifestes qui seront déployés sur Kubernetes.

Helm permet d’installer une application avec un système de templates, valeurs par défaut et valeurs par installation

Sous le capot, Helm utilise le langage de templating de Go avec (entre autres) la librairie de fonctions Sprig : vous pouvez utiliser des paramètres, mais aussi des conditions logiques, des boucles, définir des fonctions (enfin des templates) – bref, c’est puissant !

Comment utiliser Helm ?


Tout d’abord, un peu de vocabulaire : 

  • Chart : un package Helm; il est défini par son nom et sa version. Il s’agit d’un fichier tar.gz, un dossier compressé.
  • Release : une instance d’un package Helm sur un cluster Kubernetes ; il peut y avoir plusieurs releases d’un même Chart sur un cluster (à condition de leur donner des noms distincts) .
  • Manifeste : un objet Kubernetes, défini en tant que code en YAML (ou JSON).
  • Dépôt / Registre : un serveur web qui contient différentes versions d’un ou plusieurs Charts.

Création d’un package Helm

Commençons par les bases: créer un package Helm.

Pour créer un package Helm, vous pouvez utiliser la commande du binaire Helm : `helm create my-web-server`. Helm va créer un dossier `my-web-server`, dans lequel vous allez pouvoir trouver plusieurs fichiers et dossiers ; par importance :

  • Chart.yaml : fichier de métadonnées de votre Chart; contient le nom du Chart et sa version. Il contient aussi (optionnellement) les dépendances dont votre Chart pourrait avoir besoin.
  • values.yaml : les valeurs par défaut de vos paramètres. C’est ce qu’il vous faudra modifier pour donner des défauts sains à votre application lui permettant de fonctionner dans des cas généralistes.
  • templates/ : les templates qui vont être déployés par le Chart : tout fichier avec l’extension `.yaml` dans ce dossier (ou sous-dossier) sera reconnu par Helm pour être déployé sur le cluster. C’est là que le code de votre déploiement se trouvera.
  • charts/ : les éventuelles dépendances de votre Chart; et oui, Helm est un gestionnaire de paquets, et tout bon gestionnaire de paquets peut gérer des dépendances !

topographie d'un Chart fraichement créé

Avec la commande que nous avons jouée, Helm a créé un Chart pour un serveur web simple, avec beaucoup d’options modifiables ; si vous ouvrez values.yaml, vous verrez par exemple un `replica: 1`, un bloc `resources`, et plein d’autres options. Vous pouvez choisir de les surcharger lors de l’installation de votre application, ou garder ces valeurs par défaut.

Charge à vous de modifier le contenu de ces différents fichiers pour l’adapter à vos besoins.

Maintenant que nous avons un Chart valide, voyons comment le packager.

Packaging et mise à disposition d’un Chart

Si vous n’avez pas vocation à partager votre Chart en dehors de votre organisation, et qu’un déploiement depuis un dossier au lieu d’un registre ne vous dérange pas, vous pouvez juste utiliser Git pour garder les différentes versions de votre Chart.

Si vous souhaitez le partager avec d’autres entités, il faudra le packager et leur mettre à disposition.

Pour packager un Chart, c’est simple : on lance la commande `helm package my-web-server`, et Helm va compresser ce dossier dans un fichier “my-web-server-0.1.0.tgz”. Cette archive peut désormais être poussée sur un registre Helm, qui la mettra à disposition des utilisateurs.

Le registre Helm est un simple serveur web qui contient :

  • un fichier d’index à la racine  `index.yaml` qui liste tous les packages disponibles et les liens pour les télécharger
  • et les packages, souvent au format “NOM_DU_CHART-VERSION.tgz”

C’est un fonctionnement simple, et si vous ne souhaitez pas héberger vous-même le registre vous pouvez facilement configurer la plupart des providers Git pour qu’ils le fassent (GitHub Action et GitHub Pages, Gitlab Package Registry, etc).

Helm peut également utiliser des registres OCI, qui stockent les artéfacts dans des registres Docker.

Une fois que votre Chart est poussé sur le registre et que son fichier d’index a été mis à jour, il est disponible pour les utilisateurs.

Récupération d’un Chart

Pour récupérer un Chart, Helm va devoir avoir connaissance du registre où il est enregistré. En opérations normales, Helm va conserver un cache local des registres et de leurs index respectifs. Même si c’est très peu utilisé, vous pouvez vous en passer pour directement télécharger le Chart que vous appliquez.

Pour ajouter le registre et son index à notre cache local, il faut effectuer les commandes suivantes :

```
helm repo add my-repo-name http://my-repo-url
helm repo update
```

Vous pouvez alors lister les différents Charts et versions disponibles avec la commande

 `helm search repo`

Helm est maintenant configuré pour pouvoir récupérer les Charts depuis le registre my-repo-name ; pour installer un Chart enregistré sur ce registre, il nous faudra l’appeler en le préfixant par le nom que nous avons donné localement au registre ; par exemple, pour un Chart “my-web-server”, nous l'appellerons désormais “my-repo-name/my-web-server”.

Notez que le nom “my-repo-name” est exclusif à votre ordinateur ; un autre utilisateur peut le nommer comme il le souhaite. Au sein d’une même organisation, il faut mieux se synchroniser sur le nom que l’on utilise pour chaque registre, pour que la documentation soit plus simple à utiliser.

Installer mon Chart

Mon Chart est créé et est soit accessible sur mon système, soit mis à disposition sur un registre. Voyons maintenant comment nous pouvons l’installer sur notre cluster.

Une installation d’un Chart sur un cluster est appelée une Release. Un Chart peut avoir plusieurs instances sur un même cluster, identifiées chacune par des releases différentes. Bien qu’une Release ne soit pas directement un objet Kubernetes, elle est uniquement identifiée par son namespace et son nom.

Pour installer mon Chart, je peux faire un : 

`helm install webserver-001 my-repo-name/my-web-server`.

Helm va alors effectuer les actions suivantes :

  • télécharger l’archive “my-web-server” depuis le registre “my-repo-name”
  • merger les éventuelles valeurs données en ligne de commande avec les valeurs par défaut du Chart - ici, pas de surcharges, on utilise seulement les valeurs par défaut
  • générer les manifestes à installer depuis les templates
  • installer ces manifestes sur le cluster dans le namespace en cours / spécifié.
  • inscrire ces manifestes dans un fichier d’état ; par défaut, ce fichier d’état est dans un secret Kubernetes.

Votre application va désormais tourner sur le cluster !

Le fichier d’état va permettre à Helm de faire des opérations avancées sur la gestion de votre Release; tout d’abord, il va vous permettre d’effectuer rapidement des rollbacks, lorsque vous souhaitez revenir en arrière sur un déploiement. Mais surtout, il va permettre à Helm de faire des mises à jour plus propres, tenant en compte non seulement le dernier état souhaité et le nouvel état voulu, mais aussi l’état actuel de votre déploiement, ce qui va permettre aux changements manuels et automatisés de rester ; C’est très pratique lorsque vous utilisez des admissions controller par exemple. On appelle cela la réconciliation three-ways.

Helm utilise une réconciliation three-ways pour intégrer les changements manuels aux changements voulus par votre Chart.

Il n’y a pas moyen de désactiver ce comportement, et on peut s’y prendre les pieds dedans très facilement - évitez donc de toucher manuellement aux objets gérés par Helm, et tout ira bien :).

La réconciliation three-ways fait partie des rouages internes de Helm, et vous n’aurez pas besoin de savoir comment elle marche pour utiliser l’outil ; mais c’est toujours utile à connaître !

Votre serveur web devrait maintenant tourner sans problèmes, et vous pouvez vérifier son état avec un

`kubectl get pods`.


Mettre à jour ma release

Votre serveur tourne avec un seul pod; c’est bien, mais ce n’est plus suffisant pour vous ! Mettons à jour le nombre de réplicas du pod :

```helm upgrade webserver-001 my-little-repo/my-web-server –set replicas=3```

Vous devriez maintenant voir 3 réplicas tourner sur le cluster. Simple, non ? 

Sous le capot, Helm a effectué les actions suivantes : 

  • téléchargé / utilisé la dernière version du Chart “my-little-repo/my-web-server”;
  • téléchargé depuis Kubernetes le dernier état souhaité de notre application;
  • téléchargé depuis Kubernetes l’état actuel de notre application;
  • mergé la valeur “replicas=3” avec les anciennes valeurs données à notre release;
  • généré les manifestes à installer depuis les templates;
  • généré un différentiel des changements à appliquer en fonction de l’état actuel, l’ancien état souhaité et l’état voulu;
  • effectué ces changements dans Kubernetes sous forme de patchs;
  • inscrit le nouveau fichier d’état dans un Secret, qui représente le nouvel état actuel du cluster.

Mettre des paramètres dans la ligne de commande, ça ne fait cependant pas très propre ; vous pouvez créer un fichier pour les stocker et les appeler plus simplement à travers lui :

```# cat values_webserver_001.yaml
replicas: 3
resources:
 requests:
   cpu: 0.1
   memory: 200Mi
```

Vous pouvez ensuite appeler ce fichier ainsi :

```helm upgrade webserver-001 my-little-repo/my-web-server –file values_webserver_001.yaml```

Voilà, votre infrastructure Kubernetes est présentement totalement définie As Code !

Lister et supprimer mes releases

Maintenant que nous avons installé nos applications, nous pouvons les lister avec la commande suivante :

`helm ls` 

helm ls

Nous pouvons voir les différentes releases installées, avec leur Chart et la révision appliquée.

Si vous souhaitez désinstaller votre release, vous pouvez le faire avec la commande

`helm uninstall webserver-001`.

helm uninstall

Helm va se charger de supprimer tous les fichiers associés à votre release.

 

En termes de templating, quelles sont les fonctionnalités de Helm ?

Nous avons vu comment utiliser Helm, nous allons maintenant rapidement aborder les fonctionnalités qui rendent Helm si puissant.

Helm utilise le langage de templating de Golang, avec en ajout la librairie Sprig, ce qui donne beaucoup de libertés sur ce que vous souhaitez faire en termes de templates :

  • {{".Values.Variables"}} : vous pouvez bien sûr substituer une variable par une valeur dans un de vos templates, mais aussi :

  • {{" if .Values.createRBAC"}} : vous pouvez utiliser des conditions logiques (if/else) pour conditionner la création de blocs de codes, voire de certaines ressources
  • {{"range .Values.users"}}  : vous pouvez utiliser des boucles pour pouvoir répéter un bloc plusieurs fois
  • {{"include ‘my-function’ ."}}  : vous pouvez utiliser des fonctions de templating, pour éviter de répéter du code entre plusieurs ressources

On parle depuis le début de l’article des valeurs que Helm utilise pour substituer les paramètres ; Helm va utiliser les valeurs que vous lui donnez (fichier `values.yaml` et surcharges en ligne de commande), mais il va aussi mettre à disposition plusieurs interfaces pour vous donner plus d’informations :

  • “.Values.*” contient toutes les valeurs fournies explicitement par vous
  • “.Release.*” contient les informations relatives à votre Release, en particulier son nom et son namespace
  • “.Chart.*” contient les informations relatives à votre Chart, notamment son nom et sa version
  • “.Files.*”, un helper pour pouvoir accéder aux fichiers locaux ; pratique pour créer des configmaps proprement !
  • “.Capabilities”, un helper pour vérifier les capacités du cluster sur lequel on déploie ; utile pour éviter de déployer des ressources customs si elles ne sont pas définies sur le cluster !

Avec ces différents outils, vous pouvez générer la quasi - totalité des manifestes que vous souhaitez déployer - Helm est pour moi au bon endroit entre une solution pure ops et une solution pure développeur.

Helm possède aussi des fonctionnalités avancées de déploiement, qui vous permettront par exemple de définir dans quel ordre les objets doivent être créés, définir des hooks de pré et post déploiement (par exemple, pour nettoyer des données entre deux versions), ou encore définir des tests sur les objets déployés avec Helm.

Ces fonctionnalités avancées auront souvent la forme d’un Job Kubernetes, avec un label spécial reconnu par Helm - donc pas la peine d’apprendre un nouveau langage pour développer des tests !

Helm, Kustomize Ou Operators – Que choisir ?


Il y a plusieurs moyens de déployer une application sur un cluster Kubernetes, avec différents outils et méthodes. J’ai fréquemment pu voir Helm être comparé à Kustomize et même à des Operators pour faire les déploiements ; Cette section aura pour but de montrer rapidement les différences entre ces méthodes, et illustrer qu’elles n’ont pas le même public cible.

Les Operators Kubernetes permettent au travers de Custom Resources de simplifier la création d’objets. Par exemple, au lieu de créer 5 objets Kubernetes pour déployer mon serveur web, je pourrais créer une custom ressource “WebServer”, mettre tous mes paramètres dedans, et développer une application qui monitore ces custom ressources et créer les objets Kubernetes quand nécessaire. C’est utile quand vous avez beaucoup d’applications similaires, mais a plusieurs inconvénients : c’est très complexe à implémenter, nécessitant de créer, monitorer et mettre à jour régulièrement une application supplémentaire. Un opérateur nécessite aussi de garder vos manifestes WebServer à jour avec l’opérateur. En contrepartie, vous développez l’opérateur, donc vous avez une liberté totale sur comment il crée et gère sur le temps les manifestes.

Pour faire des déploiements purement Kubernetes, un opérateur sera souvent overkill car il ajoutera beaucoup de complexité pour peu de gains. Cependant, si votre application doit créer des objets en dehors de Kubernetes, comme une base de données, alors un Opérateur peut devenir une solution plus alléchante.

L’opérateur permettra aussi à des opérations de maintenance d’être effectuées automatiquement, comme par exemple des sauvegardes automatisées ou des renouvellements de certificats. C’est là un des avantages majeurs que l’opérateur aura sur les autres méthodes de déploiement.

Un opérateur permet de définir vos propres objets Kubernetes

Kustomize permet de déployer des applications au travers de bases et de patchs; C’est une solution élégante, tant qu’on n’a que très peu de modifications à apporter sur notre base. La différence la plus notable entre Helm et Kustomize est l’aspect gestionnaire de paquets. Kustomize n’a pas de packages, de versioning, ou même de rollback possible ; il peut simuler le versioning et le packaging à travers Git. Le plus gros défaut de Kustomize pour moi, vient de sa documentation : c’est un langage qui se veut fortement guidé, mais la documentation est dure à parcourir pour être capable de faire des opérations basiques.

Kustomize est aujourd’hui inclus par défaut dans le binaire de `kubectl`.

Kustomize utilise un système de patchs pour créer ses ressources

Helm est un juste milieu entre les deux : une solution de templating relativement simple à mettre en place, versionable, et auditable sur le cluster. Helm bénéficie de fonctions avancées (pre-hook, post-hooks, tests, etc) qui lui permettent de faire des rollbacks totalement automatisés - nous en parlerons dans un futur article.

Le meilleur des mondes est atteint quand vous pouvez utiliser Kustomize sur les fichiers de valeur de Helm, vous permettant ainsi de réduire au maximum la duplication de code que vous aurez sur vos déploiements. C’est par exemple possible lorsque vous utilisez du GitOps, par exemple Flux.

 

Kustomize

Helm

Operator

Complexité à implémenter 

simple

simple

complexe

Adaptabilité aux besoins

basse

haute

totale

Temps d’implémentation

bas

moyen

élevé

Temps de maintenance

moyen

bas

élevé

Gestion des déploiements précédents

non

oui

oui (selon implémentation)

Nombre d’instances
sur un cluster

1

1->N

1->N

Utilisations cibles

applications simples, peu de configuration

applications simples à complexes,
avec un souhait de partage

applications complexes ; les ressources customs d’un operator vont souvent représenter des objets non-Kubernetes, comme par exemple des certificats letsencrypt ou des topics Kafka.


En bref, si on parle uniquement d’outil de déploiement, Helm arrive en première place par rapport au ratio [temps investi / efficacité de la solution] pour la quasi-totalité des applications ; seules les applications simples bénéficieront d’un usage de Kustomize pur par rapport à Helm.

Mais une application, ça vit sur le temps, et c’est là que Helm remportera haut la main la première place, avec son aspect gestionnaire de paquets lui permettant de gérer les mises à jour d’applications simplement et proprement.

Si cette comparaison vous intéresse, vous pouvez aussi consulter cet article de techtarget qui explique en détail comment choisir entre Helm et les Opérators.

 

Conclusion

Helm est l’outil de déploiement le plus utilisé aujourd’hui sur Kubernetes, et c’est une place qu’il mérite malgré ses défauts ! Maintenir un Chart est relativement simple une fois que l’on connaît Helm, et requiert seulement des compétences de programmation simples pour le faire.

Si vous déployez des applications sur votre cluster, cherchez avant de déployer des manifestes depuis Internet s’il existe des Charts pour faire celà; c’est peut être plus compliqué aujourd’hui, mais vous me remercierez dans 6 mois quand vous voudrez faire une upgrade et que vous avez entre temps dû modifier plein de petits paramètres sur ces manifestes pour qu’ils soient mieux adaptés à votre cluster.

Une bonne ressource à utiliser pour ces recherches est artifacthub.io, qui liste la plupart des Charts disponibles sur le net.