Introduction

Notre participation au Config Management Camp 2020 nous a inspiré, à tel point qu’un article entier a été dédié à une conférence qui nous a marqué : Kubernetes Controller, not Operator.

Vous pouvez retrouver notre retour sur la conférence générale ici.

Cet article relate l’utilisation d’un Kubernetes Controller, c’est-à-dire un système qui permet d’interférer avec le cluster Kubernetes lors du cycle de vie des objets qui s’y trouvent.

La conférence

Nicolas Frankel, développeur et architecte chez Hazelcast, nous a présenté comment interférer dans la vie du cluster Kubernetes à l’aide des Controllers (et non des Operators !).

Quelques rappels pour mieux comprendre

Master/Workers

Un cluster Kubernetes est nécessairement composé de 2 éléments : Master et Worker.

  • Le Worker est le serveur sur lequel sont hébergés les conteneurs applicatifs.
  • Le Master est le serveur qui contrôle les Workers et orchestre l’armée de conteneurs déployés sur le cluster. Kubernetes fonctionne exclusivement au travers d’APIs présentes sur le Master et le Worker. Le master qui est sollicité quand nous souhaitons modifier la configuration du cluster (Pod, Deployment, etc…).

API Server

L’API server est un composant natif et installé sur le master du cluster Kubernetes. C’est lui qui est sollicité quand on veut envoyer des ordres sur le cluster.
Le composant est RESTful et formaté en JSON.

Client/Server

Les ordres que vous envoyés au cluster Kubernetes passent par un modèle client/server, où le client est sur votre poste et le server est hébergé sur le master.
Le client correspond au binaire kubectl sur votre poste.
Le server correspond à l’API server du cluster.

Il est important de corréler la version du client avec celle du server, sinon les instructions ne seront pas toutes correctement interprétées. Le modèle des API Kubernetes changent d’une version à l’autre.

Quelle est la différence entre un Controller un Operator ?

Un Controller a vocation d’interférer avec la vie du cluster (toutes les applications qui y vivent). Il sera utilisé pour appliquer un changement global et pour chaque opération sur l’API server.
Le Controller pourra par exemple enrichir une CMDB à chaque création d’un pod applicatif.

Tandis que l’Operator sera dédié à une application au travers d’un CRD (Custom Resource Definition), et enrichit l’API Kubernetes. Le principe d’un Operator est de fournir un endpoint API interne accessible par tous les objets Kubernetes pour enrichir les fonctionnalités du cluster. Les applications du cluster peuvent ainsi se baser sur ces nouveaux endpoints pour communiquer avec l’Operator.
Pour exemple, Prometheus peut être installé avec un Operator, il fournit la notion de ServiceMonitor (CRD) et PodMonitor (CRD) qui récupèrent les métriques sans devoir configurer le serveur Prometheus. Pratique, non ?

Choix du langage

Le speaker rappelle et martèle qu’un Controller peut être écrit avec n’importe quel langage, pas exclusivement Golang. Bien que Kubernetes soit écrit en Go, ce n’est pas une contrainte de langage pour l’écriture des composants satellitaires (Controller ou Operator).
L’essentiel est de discuter avec l’API server qui est RESTful et formaté en JSON, et c’est tout ! Tout le reste nous revient de droit : choix du langage/framework, coding style, etc.

Choisissez un langage que vous maîtrisez. Ne cherchez pas à réinventer votre style dans un nouveau langage, vous emploierez potentiellement des paradigmes antagonistes à ce nouveau langage.

Démonstration

Nicolas a procédé à une démonstration, en Java, sur base de son historique Git pour reprendre chaque étape de la construction de son Controller. Il nous a confrontés aux problèmes qu’il a rencontré et leurs résolutions.

Le but de la démonstration est de créer un Pod Hazelcast à chaque nouveau Pod généré sur le cluster.

Nous sommes ainsi passés par les étapes sommaires suivantes :

  • Client Java : kubernetes-client
  • RBAC Kubernetes
    • Service Account
    • Role
    • RoleBinding
  • Watcher
  • SharedIndexInformer
    • onAdd
    • onUpdate

Le début du Controller se caractérise par une simple boucle infinie sur laquelle on opère les actions à appliquer sur le cluster.

Comme le Controller est écrit en Java, il a utilisé la libraire kubernetes-client pour communiquer avec le cluster. Les premiers essais ont été confrontés aux problèmes de droits sur le cluster.

Le client kubernetes n’a pas les droits suffisants pour se connecter et nécessite l’action list au sein de son role. On créé donc un Service Account, un Role autorisant l’action list et enfin le RoleBinding qui associe les deux.

L’étape suivante est transformer une simple boucle infinie en un objet plus adapté : le Watcher. On intègre la classe java SharedInformer, elle permet d’intégrer des triggers sur des actions opérées sur le cluster : onAdd, onUpdate, etc.

Un article de l’équipe RedHat sur les triggers SharedInformer

Lien vers l’article

L’animateur a introduit l’outil Fabrik8 pour changer le mode d’implémentation de son Controller.
Fabric8 : https://github.com/fabric8io

Comme l’objectif est d’implémenter un Pod supplémentaire à partir de la création d’un Pod dans le cluster, il est important de distinguer un Pod d’un Sidecar.

Le Graal

Pour terminer la conférence, Nicolas Frankel a introduit la notion de compilation machine avec GraalVM. C’est une boite à outil pour de multiples langages qui permet de transformer un binaire à base de librairies applicatives en un binaire compilé au plus proche du langage machine.

L’application discutera ainsi directement avec le serveur et le noyau plutôt que par l’intermédiaire d’une JVM, raccourcissant ainsi l’overhead opéré par le middleware.

Les indicateurs de qualité/performance de GraalVM distingués par Nicolas sont les suivants :

  • Temps de démarrage : plus rapide
  • Langage machine du binaire : plus complexe
  • Taille du binaire : plus petit
  • Portabilité du binaire : portée par l’architecture du serveur (Linux x86_64, OS X, etc…)

Une conférence très intéressante qui couvre pas mal de sujets du moment dont Kubernetes, ses Controllers ainsi que GraalVM.

Conclusion

La conférence nous a propulsé sur l’utilisation de Kubernetes Controller pour gérer différemment la vie des objets au sein d’un cluster Kubernetes.

Pour rappel, vous pouvez retrouvez l’article général à la conférence ici.