Skip to content

Jouer à 2048 avec Kubernetes – Partie 2 : On fait nos valises

Kubernetes est un outil très utile pour déployer ses applications, comme on a pu le constater dans la première partie de cette série. Si vous ne l’avez pas encore lu, 👉session de rattrapage juste ici  

Cependant, il y a certaines choses que Kube ne peut pas résoudre ou qui sortent de son champ d’application. On trouve alors des projets qui sont développés dans l’optique de répondre aux besoins de la communauté. Aujourd’hui on va s’intéresser à l’un d’eux, Helm.

C’est quoi Helm ?

Il faut voir Helm comme « un gestionnaire de packages pour Kubernetes ». 🧳

Il est Open Source et a été créé par DeisLabs puis donné à la CNCF. L’objectif initial était de fournir une meilleure façon de gérer les fichiers Kubernetes.

Nous pouvons créer des Helm Chart, qui sont un ensemble d’un ou plusieurs manifests Kube. À l’aide d’une seule commande nous installons l’intégralité de notre application. 

Vous allez voir, c’est génial ! 😁

À noter également que Helm conserve un historique des versions de toutes les Charts déployés, afin que nous puissions rollback en cas de problème. 

Et pourquoi on va utiliser Helm alors ?

La véritable valeur ajoutée ce sont les templates, chose que kube ne fait pas et c’est ok. La promesse de l’orchestrateur est de gérer nos conteneurs, pas nos templates.

Vous êtes d’accord avec moi si je vous dis que ça rend difficile la création de manifests ? 

Mais du coup plein de questions se bouscule :

  • Est-ce que ça rend la création de manifest difficile ?
  • Comment fait-on pour utiliser différents paramètres ?
  • Doit-on les définir pour chaque fichier ?
  • Comment versionner les informations sensibles sur GitLab/GitHub ?

🤯 🤯 🤯 

Pas de panique, respirez un bon coup. ça va bien s’passer… Grâce à Helm 😎

Justement, ce “petit” outil, va nous permettre d’ajouter des variables et d’utiliser des fonctions directement dans vos fichiers.

Niquel, ça va rendre notre appli plus évolutive et on va pouvoir (éventuellement) modifier certains paramètres. 

Prêt à créer ton premier Helm Chart ? 🥰

C’est le Helm Chart, de votre vie !

Avant tout, on va avoir besoin d’installer Helm. Vous pouvez suivre la doc officielle.

Ensuite, on va taper la commande suivante : helm create <chart name> pour créer un répertoire, qui va lui-même créer d’autres répertoires et fichiers. 😅

Perso, je vais nommer mon chart game2048 :

helm create game2048

Examinons de plus près à quoi ressemblent tous ces fichiers 🔬:

  • Chart.yaml : Il inclut sa version, son nom et sa description. Dans ce fichier on peut également définir des dépendances externes.
  • values.yaml : Il s’agit du fichier qui contient les valeurs par défaut des variables, que l’on va pouvoir surcharger par la suite.
  • templates : C’est l’endroit où l’on va placer tous vos fichiers manifests qui seront créés dans Kubernetes.
  • charts : On peut importer des charts dans ce répertoire. Les dépendances de charts sont installées de bas en haut, ce qui signifie que si le chart A dépend du chart B et que B dépend de C, l’ordre d’installation sera C 👉B 👉A.

Vous vous souvenez de la phrase qui est un peu plus haut : 

Helm va nous permettre d’ajouter des variables et d’utiliser des fonctions dans vos fichiers de templates

Bah c’est exactement ce que l’on va faire !!

Variabilisatiooooon

Bon, c’est cool, on a notre chart. 😁

À présent nous allons ajouter nos fichiers dans le répertoire template, avec quelques modifications pour les rendre compatibles avec le templating go. Par exemple si l’on reprend notre manifest contenant le deployment, ça donne 👇

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: {{ include "game2048.name" . }}
  name: {{ include "game2048.name" . }}
  labels:
    {{- include "game2048.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "game2048.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "game2048.labels" . | nindent 8 }}
        {{- with .Values.podLabels }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
    spec:
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
      - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        name: {{ include "game2048.name" . }}
        securityContext:
          {{- toYaml .Values.securityContext | nindent 12 }}
        ports:
        - containerPort: {{ .Values.service.port }}
        livenessProbe:
          {{- toYaml .Values.livenessProbe | nindent 12 }}
        readinessProbe:
          {{- toYaml .Values.readinessProbe | nindent 12 }}
        resources:
            {{- toYaml .Values.resources | nindent 12 }}
        {{- with .Values.volumeMounts }}
        volumeMounts:
            {{- toYaml . | nindent 12 }}
        {{- end }}
      {{- with .Values.volumes }}
      volumes:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}

On peut ensuite tester le rendu avec la commande suivante : helm template test game2048 (les variables seront remplacées par les valeurs du fichier values.yaml)

Tadaaaaaam 🪄🪄:

apiVersion: apps/v1                                                                                                                                                                                         
kind: Deployment                                                                                                                                                                                            
metadata:                                                                                                                                                                                                   
  namespace: game2048                                                                                                                                                                                       
  name: game2048                                                                                                                                                                                            
  labels:                                                                                                                                                                                                   
    helm.sh/chart: game2048-0.1.0                                                                                                                                                                           
    app.kubernetes.io/name: game2048                                                                                                                                                                        
    app.kubernetes.io/instance: test                                                                                                                                                                        
    app.kubernetes.io/version: "1.0.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: game2048
      app.kubernetes.io/instance: test
  template:
    metadata:
      labels:
        helm.sh/chart: game2048-0.1.0
        app.kubernetes.io/name: game2048
        app.kubernetes.io/instance: test
        app.kubernetes.io/version: "1.0.0"
        app.kubernetes.io/managed-by: Helm
    spec:
      securityContext:
        {}
      containers:
      - image: "public.ecr.aws/l6m2t8p7/docker-2048:latest"
        imagePullPolicy: IfNotPresent
        name: game2048
        securityContext:
            {}
        ports:
        - containerPort: 80
        livenessProbe:
            httpGet:
              path: /
              port: 80
        readinessProbe:
            httpGet:
              path: /
              port: 80
        resources:
            {}
        volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: game2048
      volumes:
        - hostPath:
            path: /tmp/data/game2048
          name: game2048

Lorsque l’on fait cet exercice, il faut vraiment penser en mode :

“Si une autre équipe reprend mon chart pour déployer 2048, est-ce qu’elle a uniquement besoin de modifier le fichier values.yaml ?”

Si la réponse est oui, bingo, vous êtes trop fort. Sinon, il y a des chances qu’il manque un peu de templating ou de variable. 😉

Si vous voulez plus d’infos sur le template helm, j’ai écrit un article sur le blog de WeScale. 😇

⚠️ Vous trouverez tous les manifests templatisés sur le repo GitLab du projet, dans le répertoire part2

C’est quand qu’on jouuuue ?

Maintenant que nous avons notre template tout beau tout propre il va falloir paramétrer nos variables.

Rien de plus simple, éditons le fichier values.yaml

Pour ma part, il ressemble à ça :

replicaCount: 2

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  targetMemoryUtilizationPercentage: 80

image:
  repository: public.ecr.aws/l6m2t8p7/docker-2048
  pullPolicy: IfNotPresent
  tag: "latest"

podAnnotations: {}
podLabels: {}

podSecurityContext: {}

securityContext: {}

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: ""
  annotations: {}
  hosts:
	- host: game2048.127.0.0.1.nip.io
  	paths:
    	- path: /
      	pathType: Prefix
  tls: []

resources: {}

livenessProbe:
  httpGet:
	path: /
	port: 80
readinessProbe:
  httpGet:
	path: /
	port: 80

volumes:
 - name: game2048
   hostPath:
 	path: /tmp/data/game2048

volumeMounts:
 - name: game2048
   mountPath: "/usr/share/nginx/html"

nodeSelector: {}

tolerations: []

affinity: {}

Pensez à adapter les valeurs en fonction de votre contexte 😉

Les plus attentifs d’entre vous 👀auront certainement remarqué les quelques modifs’ sur le déploiement. En effet, j’en ai profité pour ajouter des liveness et readiness probe afin de bénéficier de heathchecks et de m’assurer du bon fonctionnement de mon app.

Et enfin, dernière étape avant de pouvoir jouer pendant des heures : installation du chart. 

Encore une fois, ce n’est pas bien compliqué. Il suffit d’exécuter la commande suivante :

helm upgrade game2048 . --install --namespace game2048 --create-namespace -f values.yaml

⚠️ Assurez-vous d’être dans le bon dossier. Si vous utilisez la commande précédente, il faut se placer dans projet2048/part2/game2048

Si tout est ok, vous devriez obtenir ce message : 

Release "game2048" does not exist. Installing it now.
NAME: game2048
LAST DEPLOYED: Sat Feb 10 09:44:06 2024
NAMESPACE: game2048
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
  http://game2048.127.0.0.1.nip.io/

Et voilà, on a plus qu’à se rendre sur l’URL mentionnée : http://game2048.127.0.0.1.nip.io (à adapter en fonction de la valeur renseignée dans votre fichier de values)

Et là, moment de vérité… 🥁🥁🥁

2048 web page

Ouiiiiiiiii ça fonctionne 😍😍😍

Je me fais une ptite game et on passe à la conclusion ? 🎮

Nouvel objet débloqué : Helm

Est-ce qu’il ne serait pas l’heure de débriefer un peu tout ça ?

Maintenant on peut jouer à 2048 super vite dès lors que l’on a accès à un cluster kubernetes. 🤩

Plus sérieusement, on a vu ce qu’est Helm et son fonctionnement. ça nous a permis d’aller un plus loin dans l’automatisation de notre petit jeu. Mais, je ne suis toujours pas satisfait, il reste des étapes manuelles dans le processus de déploiement (genre la commande helm upgrade –install… Clairement, est-ce que l’on n’aurait pas la flemme de (re)faire cette commande à chaque fois que l’on modifie le chart ou le fichier de values… En tout cas moi oui 😅😅

Est-ce qu’il n’existerait pas une solution pour automatiser davantage cette étape ? 🤔

ArgoCD ? Vous connaissez ? 😏

Je vous donne alors rendez-vous dans la troisième et dernière partie, dans laquelle nous allons coupler Helm et ArgoCD. On va optimiser et simplifier encore pluuuuus notre déploiement ! 🤩🤩

J’espère, que cet article vous aura donné une vision claire du potentiel et de l’intérêt d’utiliser helm dans vos projets ! N’hésitez pas à me faire des retours sur LinkedIn 😁

Published inNon classé

Comments are closed.