L'automatisation des tâches est toujours quelque chose d'assez particulier. Dès qu'on veut aller loin dans certaines tâches, il faut que l'on puisse être capable de réagir à certains évènements. Mais ces évènements ne sont pas toujours facilement écoutables, surtout à l'intérieur d'un cluster Kubernetes. Et c'est là qu'arrive ce dont on va parler aujourd'hui, le pattern Operator.
TLDR
Les opérateurs sont une extension de Kubernetes qui permet la création de ressources personnalisées afin de gérer des applications et autres composants, tout en suivant certains principes de Kubernetes comme la boucle de contrôle.
Source - Documentation Kubernetes
Qu'est-ce que le pattern Operator ?
Le pattern operator permet aux utilisateurs de Kubernetes de créer leur propre controlleur de ressources afin d'être capable de déployer et gérer de manière automatique un ensemble d'applications et de composants.
Ce pattern utilise généralement des CRD (Custom Resource Definition - ou Définition de Ressources Personnalisées) afin de permettre de faciliter la configuration de certaines tâches.
Exemple d'un CRD de Strimzi permettant de créer un cluster Kafka en quelques lignes.
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: my-cluster
spec:
kafka:
version: 3.4.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9093
type: internal
tls: true
config:
offsets.topic.replication.factor: 3
transaction.state.log.replication.factor: 3
transaction.state.log.min.isr: 2
default.replication.factor: 3
min.insync.replicas: 2
inter.broker.protocol.version: "3.4"
storage:
type: jbod
volumes:
- id: 0
type: persistent-claim
size: 100Gi
deleteClaim: false
zookeeper:
replicas: 3
storage:
type: persistent-claim
size: 100Gi
deleteClaim: false
entityOperator:
topicOperator: {}
userOperator: {}
Vu que le tout suit certains principes de Kubernetes comme la boucle de contrôle, votre opérateur pourra, selon votre configuration et de ce que vous avez défini dans votre opérateur, surveiller l'ensemble des ressources que vous avez créées (voir d'autres) et être potentiellement capable de réagir en fonction de certains évènements grâce à l'API Kube. (Notamment pour pouvoir régler automatiquement certains soucis)
Voici un schéma de RedHat décrivant le contexte.
Exemple
Afin d'être plus concret, voici des exemples.
1. Automatiser pour éviter la création de ressources identiques manuellement
Vous êtes dans une équipe qui donne aux autres équipes de votre entreprise, l'ensemble des outils pour qu'ils puissent collecter et visualiser leurs métriques de manière complètement indépendante.
Ce qui signifie que pour chacun de vos clients, vous devez déployer et gérer manuellement :
- Prometheus
- OpenTelemetry
- Grafana
- Postgres
Dans cette situation, au lieu d'avoir à répéter dans votre coin l'ensemble des actions pour pouvoir déployer ces applications et l'ensemble des composants (Services, configmap, service accounts...) associés, vous pouvez créer un opérateur pour pouvoir gérer ces manipulations pour vous et créer un CRD pour permettre de configurer les quelques points qui peuvent varier d'une stack à l'autre.
Le CRD ici s'appellerait ObservabilityStack
et lorsque que vous allez créer une instance de cette ressource, ça va automatiquement créer et configurer correctement l'ensemble des ressources associées à la stack..
2. Automatiser pour éviter les erreurs manuelles en cas de création/mise à jour/suppression
Ceux qui ont déjà gérer des StatefulSet
vont comprendre de suite de quoi je parle ici. En effet, quand on gère certaines applications, surtout celles avec des volumes associés, il se peut qu'une création, une mise à jour ou une suppression demande l'exécution de tout un ensemble de commandes dans un ordre précis afin d'être sûr que tout se passe bien.
Quand on en a 3-4, ça reste correct de gérer ça avec des scripts bash ou ansible. Mais quand on en a 400, 500 ou plus?
Dans ce genre de situation, le pattern operator vient aussi vous aider. Vous êtes capables de définir un ensemble d'actions de manière automatisée qui va s'exécuter automatiquement dès qu'un évènement de création, mise à jour ou suppression va être détecté.
Ainsi, ces applications ne sont plus dépendantes de vous pour être mises à jour et ça va clairement vous faciliter la vie et vous faire gagner du temps.
3. Configuration automatique
Dans cet exemple, on va imaginer que vous êtes dans une équipe qui gère un Nginx qui sert de gateway pour l'ensemble des apis de votre entreprise. Dès qu'une nouvelle api est créée, vous devez l'ajouter dans les fichiers de configurations de tous vos environnements. Et vu que votre entreprise est très portée sur les microservices, vous avez des demandes quasiment toutes les semaines.
De plus, certaines apis sont renommées, déplacées ou même supprimées, mais vous n'êtes pas toujours tenu au courant, du coup dès qu'une api ne fonctionne plus, on vient vous voir pour vous demander pourquoi l'api X n'est plus accessible?
Comme vous l'avez compris, l'opérateur vient à nouveau vous aider! En effet, vu que vous pouvez surveiller des ressources qui "n'appartiennent pas à l'opérateur" (autrement dit des ressources qui n'ont pas été crées par l'opérateur et qui ne sont pas gérées par l'opérateur), vous pouvez surveiller l'ensemble des services créés sur votre cluster pour mettre à jour automatiquement votre configuration dès qu'un service est créé, mis à jour et/ou supprimé.
4. Surveillance automatique
Pour le dernier exemple, imaginez que vous faites parti d'une équipe de support dont les applications sont toutes déployées dans un cluster Kubernetes. Certaines de ces applications peuvent avoir des pods qui crashent et qui nécessitent une manipulation particulière pour pouvoir les redémarrer proprement.
Comme on a pu l'évoquer précédemment, l'opérateur est capable d'exécuter toute une suite d'action que l'on a programmer. Du coup, il pourrait être capable d'exécuter ce qu'il faut pour pouvoir redémarrer proprement les applications.
Mais comment faire pour l'activer dès qu'il y a une erreur ?
Actuellement, ça n'est pas possible de l'activer dès qu'il n'y a une erreur. Mais il faut savoir que par défaut un opérateur effectue une vérification des ressources qu'il gère toutes les 10h. Du coup, si vous avez un opérateur qui ne gère le redémarrage de vos applications, vous pouvez le faire rouler bien plus régulièrement. (Bien évidemment ça dépendra de la criticité de vos applications, vos objectifs de disponibilité ...)
Bon là, avec tous ces exemples, je pense que vous comprenez le principe et l'utilité d'un tel pattern.
Maintenant, si on veut aller plus loin pour comprendre comment ça fonctionne un peu plus dans le détail, il faut mettre les mains dedans. Du coup, on va se donner rendez-vous dans la suite de cet article où on va voir comment créer un opérateur!
J'espère que ça vous aidera et si jamais vous avez des questions, quelles qu'elles soient (Il n'y a jamais de questions bêtes!) ou des points qui ne sont pas clairs pour vous, n'hésitez pas à laisser un message dans les commentaires ou à me joindre directement sur LinkedIn (même pour parler d'autres sujets!).
Top comments (2)
Très intéressant, merci 🙏
Peut-être mettre un exemple de CRD pour susciter notre intérêt encore plus, avant de montrer comment mettre ça en place.
Par exemple, configurer un cluster kafka avec simplement quelques paramètres : github.com/strimzi/strimzi-kafka-o...
Hâte de lire la suite 😃
Ravi que ça te plaît et j'espère que la suite te ravira tout autant.
Concernant l'exemple, c'est vrai que c'est une bonne idée et que ça aiderait en effet à avoir un exemple concret concernant la puissance des opérateurs! Merci pour la suggestion :)