Contactez-nous

Développer un Operator simple (aperçu)

Obtenez un aperçu du développement d'un Operator Kubernetes simple : outils (Operator SDK, Kubebuilder), étapes clés (API, contrôleur), et considérations de déploiement.

De l'idée à l'automatisation : les bases du développement d'Operator

Maintenant que nous comprenons ce qu'est un Operator et sa valeur ajoutée grâce aux CRDs, une question naturelle se pose : comment en construit-on un ? Bien que le développement d'un Operator robuste demande un effort certain et une bonne compréhension de Kubernetes et du langage de programmation choisi (le Go étant le plus courant), l'écosystème fournit des outils et des bibliothèques pour grandement simplifier le processus.

Cet aperçu ne vise pas à être un tutoriel complet, mais plutôt à démystifier les étapes principales et les outils impliqués dans la création d'un Operator simple. Nous nous concentrerons sur l'approche la plus répandue utilisant Go et les frameworks dédiés.

Les outils du développeur d'Operator : SDK et Kubebuilder

Plutôt que de partir de zéro pour interagir avec l'API Kubernetes, gérer les boucles de contrôle, etc., les développeurs s'appuient généralement sur des frameworks qui fournissent un squelette de projet et des abstractions utiles. Les deux plus populaires dans l'écosystème Go sont :

  • Operator SDK : Un projet initié par Red Hat (faisant partie du Operator Framework). Il fournit des outils en ligne de commande pour générer le projet, les CRDs, les contrôleurs et les manifestes de déploiement. Il supporte différents types d'Operators (Go, Ansible, Helm).
  • Kubebuilder : Un projet initié par Google, qui est en fait la base sur laquelle repose une grande partie de l'Operator SDK pour les Operators Go. Il se concentre sur la génération de projets Go en utilisant les bibliothèques controller-runtime et controller-tools pour l'interaction avec l'API et la génération de code/manifestes.

Ces outils partagent de nombreuses dépendances et concepts sous-jacents, notamment l'utilisation de controller-runtime, une bibliothèque qui simplifie grandement l'écriture de contrôleurs Kubernetes en gérant les watchs sur les ressources, les files d'attente de travail, la mise en cache des objets et le lancement des boucles de réconciliation.

Ils utilisent également controller-tools pour générer automatiquement du code (comme les clients typés pour les CRDs) et des manifestes (CRD YAML, RBAC YAML) à partir de marqueurs spéciaux (commentaires formatés) dans le code Go.

Etapes clés du développement d'un Operator Go

Le processus typique de développement d'un Operator avec Kubebuilder ou l'Operator SDK suit ces étapes générales :

  1. Initialisation du projet : Utilisation de la CLI du framework pour créer la structure du projet.
    # Exemple avec Kubebuilder
    kubebuilder init --domain example.com --repo github.com/my-user/my-operator
  2. Définition de l'API (CRD) : Création d'un nouveau type d'API. Le développeur définit la structure de la CRD (les champs de spec et status) dans un fichier Go (par exemple, api/v1/myapp_types.go) en utilisant des structures Go et des marqueurs spéciaux (comme // +kubebuilder:subresource:status ou // +kubebuilder:validation:Required).
    # Commande pour créer la structure de l'API
    kubebuilder create api --group myapp --version v1alpha1 --kind MyApp
    // api/v1alpha1/myapp_types.go
    
    // MyAppSpec defines the desired state of MyApp
    type MyAppSpec struct {
    	// +kubebuilder:validation:Minimum=1
    	// +kubebuilder:validation:Required
    	Replicas int32  `json:"replicas"`
    	Image    string `json:"image"`
    }
    
    // MyAppStatus defines the observed state of MyApp
    type MyAppStatus struct {
    	// +kubebuilder:validation:Optional
    	AvailableReplicas int32 `json:"availableReplicas,omitempty"`
    }
    
    // +kubebuilder:object:root=true
    // +kubebuilder:subresource:status
    // MyApp is the Schema for the myapps API
    type MyApp struct {
    	metav1.TypeMeta   `json:",inline"`
    	metav1.ObjectMeta `json:"metadata,omitempty"`
    
    	Spec   MyAppSpec   `json:"spec,omitempty"`
    	Status MyAppStatus `json:"status,omitempty"`
    }
  3. Génération des Manifestes et du Code : Exécution d'une commande du framework (par exemple, make manifests generate) qui utilise controller-tools pour générer le manifeste YAML de la CRD (dans config/crd/bases/) et le code client Go nécessaire à partir des types définis.
  4. Implémentation du Contrôleur (Logique de Réconciliation) : C'est le coeur du travail. Le développeur implémente la fonction Reconcile dans le fichier du contrôleur (par exemple, controllers/myapp_controller.go). Cette fonction contient la logique métier :
    • Récupérer l'instance de la CR qui a déclenché la réconciliation.
    • Récupérer l'état actuel des ressources gérées par l'Operator (par exemple, un Deployment) via le client Kubernetes fourni par controller-runtime.
    • Comparer l'état désiré (tiré de la spec de la CR) avec l'état actuel.
    • Effectuer les actions nécessaires (créer le Deployment s'il n'existe pas, le mettre à jour si le nombre de réplicas ou l'image a changé, etc.).
    • Mettre à jour le champ status de la CR pour refléter l'état actuel observé.
    • Gérer les erreurs et retourner un résultat indiquant si la réconciliation doit être retentée (et avec quel délai).
  5. Configuration du Contrôleur (main.go) : Le fichier main.go, largement généré par le framework, configure le "manager" controller-runtime qui enregistre le schéma de la CRD, initialise le contrôleur, et lui indique quelles ressources surveiller (la CR elle-même, mais aussi les ressources que l'Operator crée, comme un Deployment, pour pouvoir réagir à leurs changements).
  6. Gestion RBAC : En utilisant des marqueurs dans le code du contrôleur (par exemple, //+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete), le développeur spécifie les permissions nécessaires à l'Operator. Le framework génère ensuite les manifestes YAML pour les Roles/ClusterRoles et RoleBindings/ClusterRoleBindings correspondants.

Construction, test et déploiement

Une fois la logique implémentée, le processus continue avec :

  • Construction de l'image : Un Dockerfile (généralement fourni par le framework) est utilisé pour construire l'image conteneur de l'Operator.
  • Tests : Il est crucial de tester l'Operator. Cela inclut des tests unitaires pour la logique de réconciliation et des tests d'intégration/end-to-end (souvent en utilisant des outils comme envtest qui démarre un environnement de test Kubernetes léger) pour vérifier le comportement de l'Operator dans un cluster simulé ou réel.
  • Déploiement : Le framework génère les manifestes nécessaires pour déployer l'Operator sur un cluster Kubernetes :
    • Le manifeste de la CRD.
    • Les manifestes RBAC (ClusterRole, ClusterRoleBinding ou Role, RoleBinding).
    • Un manifeste de Deployment pour exécuter le code de l'Operator lui-même dans un Pod.
    L'application de ces manifestes (kubectl apply -k config/default ou via Kustomize/Helm) déploie l'Operator.

Un aperçu simplifié

Cet aperçu simplifie volontairement certains aspects. Le développement d'un Operator de production implique de gérer des cas complexes comme les migrations de version de CRD, l'utilisation de finalizers pour la suppression propre des ressources externes, une gestion d'erreurs robuste, l'implémentation de webhooks d'admission pour la validation ou la mutation des CRs, et une stratégie de test approfondie.

Cependant, grâce aux frameworks comme Operator SDK et Kubebuilder, les développeurs disposent d'une base solide et d'outils efficaces pour se concentrer sur l'essentiel : encoder la logique opérationnelle spécifique à leur application dans la boucle de réconciliation du contrôleur. Cela rend le développement d'automatisation Kubernetes-native beaucoup plus accessible qu'auparavant.