Lasso est un framework de contrôleur.
Lasso a une certaine parité fonctionnelle avec le projet d'exécution du contrôleur et pourrait être utilisé à la place du temps d'exécution du contrôleur.
Le lasso est de bas niveau. Si vous souhaitez gérer vos propres contrôleurs, vous pouvez l'utiliser. Si vous recherchez plus de commodité et de fonctionnalités pour créer vos propres types de ressources, nous vous recommandons de consulter Wrangler.
Framework de contrôleur de base utilisé par Wrangler et Norman.
Ce document a été rédigé en pensant à deux publics : quelqu'un qui est nouveau dans les contrôleurs Kubernetes et quelqu'un qui n'est pas nouveau dans les contrôleurs Kubernetes mais qui est nouveau dans le lasso.
Si vous appartenez à la catégorie « Quelqu'un qui n'est pas nouveau dans les contrôleurs Kubernetes », vous pouvez passer directement à la proposition de valeur de Lasso.
Si vous débutez avec les contrôleurs Kubernetes, il est recommandé de ne sauter aucune section.
Si vous ne disposez pas de connaissances de base sur Kubernetes, il est recommandé de consulter d'abord une autre documentation sur les bases, telle que la présentation de Kubernetes.
Remarque : Il s’agira d’un cours intensif très bref. Nous vous encourageons à rechercher d’autres ressources sur le sujet, il y en a beaucoup ! Deux ressources recommandées sont le projet Sample Controller et l’introduction aux frameworks de contrôleur Kubernetes.
Extrait de la documentation Kubernetes
Dans Kubernetes, un contrôleur est une boucle de contrôle qui surveille l'état partagé du cluster via le serveur API et apporte des modifications en tentant de déplacer l'état actuel vers l'état souhaité.
Le mot « contrôleur » est utilisé de manière plus vague que ce que la définition ci-dessus pourrait vous faire croire. Selon nos propres mots : les contrôleurs sont des gestionnaires de boucles qui agissent en réponse aux événements de ressources Kubernetes. Dans Lasso, nous utilisons également le mot « contrôleur » pour désigner l'ensemble de la structure chargée d'enregistrer ce gestionnaire de boucle et de lui fournir les ressources dont il a besoin. En bref, les contrôleurs sont des structures qui regroupent tout le nécessaire pour interagir et fonctionner sur les types Kubernetes.
Afin d’atteindre l’objectif ci-dessus, quelques sous-objectifs doivent être atteints :
Il existe de nombreux cadres pour aider à atteindre les objectifs ci-dessus. Le lasso en fait partie. Ce que la plupart de ces frameworks ont en commun, y compris le lasso, c'est qu'ils utilisent les fonctionnalités du client-go pour atteindre ces objectifs. Vous pouvez atteindre ces objectifs en utilisant simplement client-go. Pour le reste de cette section, nous verrons comment un contrôleur est créé en utilisant simplement les concepts client-go.
Un informateur est utilisé pour atteindre les objectifs ci-dessus nécessaires à un contrôleur Kubernetes. Un informateur possède un gestionnaire d’événements et un indexeur. L'indexeur possède des fonctions de magasin et de carte pour indexer les objets dans le magasin appelés indexeurs. Les structures sous-jacentes sont différentes, mais une pseudo-structure est présentée ci-dessous pour illustrer cela :
Informer
EventHandler
Indexer
Store
Indexers
EventHandler peut avoir une logique différente pour créer, mettre à jour et supprimer des événements. Le gestionnaire d'événements est l'endroit où le contrôleur entre en jeu. Vous l'utilisez pour configurer les gestionnaires d'événements de création, de mise à jour et de suppression.
L'indexeur est utilisé comme cache.
Le magasin est l'endroit où l'indexeur conserve les objets.
Les indexeurs sont des fonctions que l'indexeur peut utiliser pour indexer des objets persistants. Une fois indexés avec un indexeur, les objets peuvent être récupérés à l'aide de chaînes décrivant une caractéristique qui intéresse l'indexeur.
L'indexeur sera souvent utilisé pour récupérer un objet par de simples métadonnées telles que l'espace de noms et le nom.
L'informateur remplit d'abord l'indexeur en répertoriant toutes les ressources renvoyées par un client. L’informateur surveille ensuite la ressource Kubernetes à laquelle il est affecté. Lorsqu'un événement survient, il utilise cet événement pour mettre à jour son indexeur et exécuter ses gestionnaires d'événements.
Habituellement, une application nécessite plusieurs contrôleurs. Cependant, il n’est peut-être pas efficace que chaque contrôleur ait son propre informateur et donc son propre indexeur. Le SharedIndexerInformer de client-go peut être utilisé pour ajouter plusieurs contrôleurs qui utilisent tous les mêmes indexeurs.
Il existe un excellent visuel de la façon dont un contrôleur Kubernetes pourrait fonctionner dans le dépôt kubernetes/sample-controller.
Remarque : Les informateurs ont été simplifiés par souci de concision. Si vous êtes intéressé par leur fonctionnement exact, il est recommandé de lire le code client-go.
Lasso standardise ce qu'est un contrôleur avec son package de contrôleur. Lasso présente des usines pour gérer les caches, les contrôleurs et les clients au sein d'un projet. Ceci est impératif pour un éleveur qui gère de nombreuses instances de nombreux types.
Le contrôleur lasso utilise la file d'attente de travail client-go. Lasso enregistre un gestionnaire d'événements qui traite la file d'attente de travail. Le gestionnaire orienté file d'attente de travail fait qu'un seul gestionnaire d'événements doit être ajouté pour chaque type Kubernetes. Désormais, l'enregistrement d'un gestionnaire l'ajoute simplement à la liste des gestionnaires du contrôleur du type. La mise en file d'attente d'un objet l'ajoute à la file d'attente de travail. Chaque objet de la file d'attente de travail sera ensuite traité par des travailleurs exécutés dans des goroutines. Le gestionnaire d'événements du contrôleur remettra en file d'attente tout objet qui amène un ou plusieurs gestionnaires du contrôleur à renvoyer une erreur qui n'est pas de type ErrIgnore
. Cette file d'attente de travail peut également contenir des objets provenant d'autres sources. Cette fonctionnalité est exposée via la fonction Enqueue du contrôleur. Cela transforme les contrôleurs qui ne sont plus uniquement réactifs aux ressources Kubernetes et aux resynchronisations du cache, mais qui peuvent également être invoqués par code.
Le type sharedController intègre l'interface Controller pour exposer les fonctionnalités de son contrôleur. Le sharedController expose également la fonction RegisterHandler ainsi que la fonction Client. RegisterHandler ajoute le gestionnaire transmis à la liste des gestionnaires du contrôleur et Client renvoie un client pour le type de ressource correspondant à sharedController ; sharedController a un champ GVK (Group Version Kind) qui indique à quel type il est destiné.
L'aspect "Partagé" commence au contrôleur Lasso plus primitif. L'utilisation d'une file d'attente de travail permet par exemple de partager un ensemble de gestionnaires d'événements. Ensuite, le contrôleur partagé Lasso ajoute à cela en conservant un client réutilisable pour le GVK et en ajoutant un moyen d'enregistrer facilement les gestionnaires auprès du contrôleur en dessous avec RegisterHandler.
Le sharedController peut créer son contrôleur sous-jacent. Il ne le fera qu’une fois qu’un gestionnaire sera enregistré auprès du sharedController.
Encapsule le client Kubernetes. Contient les champs GVK pour gérer le client dans une structure parent telle que sharedClientFactory. Expose des fonctionnalités supplémentaires telles que la configuration de l'en-tête User-Agent pour le client REST sous-jacent.
Le cache lasso est un wrapper léger autour d'un SharedIndexInformer du client-go.
Le principal avantage du Lasso Cache est qu'il peut se voir attribuer une Cache Factory, qui gère SharedIndexInformer en mémoire par GVK afin qu'ils puissent être réutilisés. Lors de l'utilisation des fonctions Lasso Cache, il se gérera lui-même dans le CacheFactory qui a été transmis pour le créer.
La fabrique de cache partagé stocke les caches et permet de les gérer via les structures GVK. Une fois les caches créés, ils peuvent être réutilisés.
La Shared Client Factory existe pour qu'un client pour un GVK puisse être réutilisé après sa création.
SharedControllerFactory relie tout ce qui précède. Il permet à un point d'entrée unique d'accéder aux clients, aux caches et aux gestionnaires, qu'il gère pour vous. Il est possible d’interagir principalement avec la fabrique de contrôleurs partagés. Il créera tous les contrôleurs, clients et caches sous-jacents dont vous avez besoin. Cela garantira qu’il n’y a pas de doublons de ces objets. Cela empêchera les conditions de course.
Une fois que vous utilisez ForObject, ForKind, ForResource ou ForResourceKind, SharedControllerFactory effectuera les opérations suivantes :
Le deferredController est une fonction qui, une fois exécutée, créera et renverra un contrôleur. Il créera le contrôleur en utilisant un cache de SharedCacheFactory. Le but de la fonction deferredController est de ne pas remplir le cache jusqu'à ce que cela soit absolument nécessaire. Cela garantit que seules les ressources Kubernetes qui ont des gestionnaires enregistrés, ont été mises en file d'attente ou dont le cache de leur contrôleur a été demandé sont stockées en mémoire.
Lorsque vous obtenez un sharedController de SharedControllerFactory, aucun contrôleur sous-jacent n'est encore instancié. Il appellera plutôt la méthode deferredController pour en créer une une fois l’une des opérations mentionnées effectuée.
Vous trouverez ci-dessous les étapes permettant d'enregistrer facilement des gestionnaires et de les exécuter au lasso :
package main
import (
"context"
"github.com/rancher/lasso/pkg/controller"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
)
func main () {
config , err := clientcmd . BuildConfigFromFlags ( "" , os . Getenv ( "KUBECONFIG" ))
if err != nil {
panic ( err )
}
// Setup types you want to work with
scheme := runtime . NewScheme ()
appsv1 . AddToScheme ( scheme )
controllerFactory , err := controller . NewSharedControllerFactoryFromConfig ( config , scheme )
if err != nil {
panic ( err )
}
// ForObject, ForKind, ForResource, and ForResourceKind can all be used to retrieve the controller.
// They all accept different parameters but the first three all eventually call ForResourceKind.
// Refer to [How to use Lasso](#how-to-use-lasso) for more information on how ForResourceKind works.
sharedController , err := controllerFactory . ForObject ( & appsv1. Deployment {})
if err != nil {
panic ( err )
}
// Register a handler on a shared controller. If you need a dedicated queue then use controller.New()
sharedController . RegisterHandler ( context . TODO (), "my-handler" , controller . SharedControllerHandlerFunc ( func ( key string , obj runtime. Object ) (runtime. Object , error ) {
// obj is the latest version of this obj in the cache and MAY BE NIL when an object is finally deleted
dep , ok := obj .( * appsv1. Deployment )
if ! ok {
return obj , nil
}
// Do some stuff ...
// Get stuff from the cache
sharedController . Informer (). GetStore (). Get ( key )
result := & appsv1. Deployment {}
err := sharedController . Client (). Update ( ctx , dep . Namespace , dep , result , metav1. UpdateOptions {})
// return the latest version of the object
return result , err
}))
// the second, int parameter is the number of workers to be used for EACH controller.
err = controllerFactory . Start ( context . TODO (), 5 )
if err != nil {
panic ( err )
}
}
Certains tests de Lasso utilisent envtest pour s'exécuter. Envtest permet d'exécuter des tests sur un "faux" serveur Kubernetes avec peu ou pas de surcharge.
Pour installer le binaire setup-envtest
requis, utilisez la commande suivante :
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
Avant d'exécuter les tests, vous devez exécuter la commande suivante pour configurer le faux serveur :
# note that this will use a new/latest version of k8s. Our CI will run against the version of k8s that corresponds to lasso's
# current client-go version, as seen in scripts/test.sh
export KUBEBUILDER_ASSETS= $( setup-envtest use -p path )
Les ressources suivantes ont été utiles pour rédiger ces documents. Ils sont fortement recommandés pour en savoir plus que ce qui est présenté ici :