当前位置:网站首页>Analyse approfondie de kubebuilder
Analyse approfondie de kubebuilder
2022-07-07 04:45:00 【Chenxy02】
Site Web de référence:
Introduction - The Kubebuilder Book
Analyse approfondie Kubebuilder:Écrire CRD Plus simple - Oui.
Guide de lecture
Recommandez à vos amis de lire les documents officiels ci - dessus.
J'ai envoyé un blog. Basé surKubebuilderDéveloppementOperator(Démarrer avec)_chenxy02Blog de-CSDNBlogs C'est noté.kubebuilderPour commencer à utiliser, Cet article vise à approfondir la compréhension kubebuilderShenzhen,En savoir pluskubebuilderCode du projet pour.
Concept de base
GVKs & GVRs
GVK = GroupVersionKind,GVR = GroupVersionResource
- Pendant le codage, Les données sur les ressources sont stockées dans une structure (AppeléGo type)
- En raison de plusieurs versions versionL'existence de(alpha1, beta1, v1Attendez.), Il existe des différences dans les structures de stockage entre les versions , Mais nous lui donnerons tous le même KindNom(Par exemple,Deployment)
- Donc,, On encode SeulementkindNom(Par exemple:Deployment), Il n'est pas possible d'obtenir exactement quelle version de la structure elle utilise
- Alors...,AdoptionGVK Obtenir une structure de stockage spécifique ,C'est - à - direGVKTrois messages pour(group/version/kind)Identifier unGo type(Structure)
Comment obtenir? —— AdoptionScheme,SchemeStockéGVKEtGo TypeRelations cartographiques pour
- Lors de la création de la ressource ,Nous avons écrityaml,Soumettre une demande:
- CompilationyamlEn cours, Nous écrirons apiversionEtkind,En fait, c'estGVK
- Et le client(C'est nous.)AvecapiserverLa correspondance esthttpForme, Envoyer une demande à un http path
Envoyé à quelhttp pathEt alors??——C'esthttp pathEn fait, c'estGVR
- /apis/batch/v1/nampspaces/default/job C'est ce que ça veut dire.default De l'espace de nomsjobRessources
- Nous kubectl get po Heure C'est aussi le chemin demandé ,Aussi appeléGVR
- En fait... GVR C'est par GVK Ça se transforme en —— AdoptionRESTCartographiéRESTMappersRéalisation
Scheme
Chaque groupeControllersJ'en ai besoin.Scheme,OffreKindsCorrespondantGo typesCartographie de,C'est - à - direCompte tenu deGo type Je savais que GVK,Compte tenu deGVK Je savais que Go type
Manager
Kubebuilder Éléments de base,Avec 3 Responsabilités:
Responsable de l'exécution de tous les Controllers;
Initialiser le partage cashes,ContientlistAndWathFonction
InitialisationclientsPourApi ServerCommunications
Cache
KubebuilderÉléments de base,Responsable deController Le processus est basé sur SchemeSynchroniserApi Server Tout ce qui ControllerAttention.GVKsDeGVRs,Son cœur estGVK->InformerCartographie de,Informer Sera responsable de l'écoute des correspondances GVKDeGVRsCréation de/Supprimer/Opération de mise à jour,Pour déclencherControllerDeReconcileLogique.
Controller
Kubebuilder Fichiers d'échafaudage générés pour nous ,Nous devons juste réaliserReconcileLa méthode est juste.
Clients
En cours de réalisationController Il est in évitable de créer certains types de ressources /Supprimer/Mise à jour,C'est par là.ClientsRéalisé, Où la fonction de requête la requête réelle est locale Cache, Accès direct aux opérations d'écriture Api Server
Index
Parce queController Oui, souvent. CacheEffectuer une requête,KubebuilderOffreIndex utilityVoilà.Cache L'efficacité de la requête est améliorée .
Finalizer
En général, Si la ressource est supprimée , Bien que nous puissions déclencher un événement de suppression , Mais cette fois, depuis Cache Impossible de lire les informations sur les objets supprimés à l'intérieur ,C'est comme ça., Cela a entraîné de nombreux travaux de nettoyage des ordures qui n'ont pas pu être effectués en raison d'une information insuffisante .
K8sDeFinalizer Les champs sont utilisés pour traiter cette situation .InK8sMoyenne,Tant que l'objetObjectMetaÀ l'intérieur.FinalizersPas vide,Pour cet objetdelete L'opération se transforme en updateFonctionnement,Plus précisémentupdate deletionTimestampChamp, Ça veut dire dire K8sDeGC“IndeletionTimestamp Après ce moment ,Tant queFinalizerVide, Supprimer immédiatement l'objet “.
Donc, l'utilisation générale de la pose est de créer un objet avec Finalizers C'est réglé.(Arbitraire string),Et on s'en occupe. DeletionTimestamp Pas vide update Fonctionnement(En fait, delete),Selon Finalizers La valeur de a fait tout pre-delete hook(Vous pouvez maintenant Cache Toute information lue à l'intérieur de l'objet supprimé )Après Finalizers Laisser en blanc.
OwnerReference
k8s GC Lors de la suppression d'un objet ,N'importe quoiownerReference Les objets qui sont cet objet sont effacés ,En même temps,,kubebuilder Prise en charge des modifications pour tous les objets DéclencheOwnerObjetcontrollerDeReconcileMéthodes.
Tous les concepts sont regroupés comme suit :

Lecture du code source
Le code suivant provient de Basé surKubebuilderDéveloppementOperator(Démarrer avec)_chenxy02Blog de-CSDNBlogs
Demain.goC'est parti.
Kubebuilder Créé main.go Est l'entrée de l'ensemble du projet,La logique est simple.:
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(webappv1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
func main() {
...
// 1、Manager
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "ecaf1259.my.domain",
})
...
// 2、init Reconciler(Controller)
if err = (&controllers.GuestbookReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Guestbook")
os.Exit(1)
}
...
// 3、start Manager
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}Comme vous pouvez le voir dans init Dans la méthode, nous allons webappv1Inscrivez - vous àSchemeC'est parti.,C'est comme ça.CacheJe le savais.watchQui est - ce?,main La logique de la méthode est essentiellement ManagerDe:
- Initialisé unManager;
- Oui.Manager De Client Transmis à Controller,Et appelle SetupWithManager Méthode entrée Manager En cours Controller Initialisation de;
- DémarrageManager
ManagerInitialisation
ManagerLe Code d'initialisation est le suivant:
// New returns a new Manager for creating Controllers.
func New(config *rest.Config, options Options) (Manager, error) {
// Set default values for options fields
options = setOptionsDefaults(options)
cluster, err := cluster.New(config, func(clusterOptions *cluster.Options) {
clusterOptions.Scheme = options.Scheme
clusterOptions.MapperProvider = options.MapperProvider
clusterOptions.Logger = options.Logger
clusterOptions.SyncPeriod = options.SyncPeriod
clusterOptions.Namespace = options.Namespace
clusterOptions.NewCache = options.NewCache
clusterOptions.ClientBuilder = options.ClientBuilder
clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor
clusterOptions.DryRunClient = options.DryRunClient
clusterOptions.EventBroadcaster = options.EventBroadcaster
})
...
return &controllerManager{
cluster: cluster,
recorderProvider: recorderProvider,
resourceLock: resourceLock,
metricsListener: metricsListener,
metricsExtraHandlers: metricsExtraHandlers,
logger: options.Logger,
elected: make(chan struct{}),
port: options.Port,
host: options.Host,
certDir: options.CertDir,
leaseDuration: *options.LeaseDuration,
renewDeadline: *options.RenewDeadline,
retryPeriod: *options.RetryPeriod,
healthProbeListener: healthProbeListener,
readinessEndpointName: options.ReadinessEndpointName,
livenessEndpointName: options.LivenessEndpointName,
gracefulShutdownTimeout: *options.GracefulShutdownTimeout,
internalProceduresStop: make(chan struct{}),
leaderElectionStopped: make(chan struct{}),
}, nil
}Je vois. Principalement pour créerCacheAvecClients Attends, attends un exemple :
CréationCache
Cache Le Code d'initialisation est le suivant:
// New initializes and returns a new Cache.
func New(config *rest.Config, opts Options) (Cache, error) {
opts, err := defaultOpts(config, opts)
if err != nil {
return nil, err
}
im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace)
return &informerCache{InformersMap: im}, nil
}
// NewInformersMap creates a new InformersMap that can create informers for
// both structured and unstructured objects.
func NewInformersMap(config *rest.Config,
scheme *runtime.Scheme,
mapper meta.RESTMapper,
resync time.Duration,
namespace string) *InformersMap {
return &InformersMap{
structured: newStructuredInformersMap(config, scheme, mapper, resync, namespace),
unstructured: newUnstructuredInformersMap(config, scheme, mapper, resync, namespace),
metadata: newMetadataInformersMap(config, scheme, mapper, resync, namespace),
Scheme: scheme,
}
}Je vois.CachePrincipalement crééInformersMap, Scheme Chacun à l'intérieur GVK Les deux ont créé des Informer,Adoption informersByGVK C'est map Fais - le. GVK À Informer Cartographie de,ChaqueInformerSera basé surListWatch La paire de fonctions correspond à GVKEn coursListEtWatch.
Création Clients
Création Clients C'est simple.:
// defaultNewClient creates the default caching client
func defaultNewClient(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) {
// Create the Client for Write operations.
c, err := client.New(config, options)
if err != nil {
return nil, err
}
return &client.DelegatingClient{
Reader: &client.DelegatingReader{
CacheReader: cache,
ClientReader: c,
},
Writer: c,
StatusClient: c,
}, nil
}L'opération de lecture utilise Cache,Les opérations d'écriture utilisent K8s go-client Connexion directe.
ControllerInitialisation
Regarde par là.ControllerDémarrage:
// SetupWithManager sets up the controller with the Manager.
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&webappv1.Guestbook{}).
Complete(r)
}En service BuilderMode,NewControllerManagerByEtFor Toutes les méthodes sont données à BuilderPasser le ginseng, Le plus important est la dernière méthode Complete,La logique est:
func (blder *Builder) Build(r reconcile.Reconciler) (manager.Manager, error) {
...
// Set the Manager
if err := blder.doManager(); err != nil {
return nil, err
}
// Set the ControllerManagedBy
if err := blder.doController(r); err != nil {
return nil, err
}
// Set the Watch
if err := blder.doWatch(); err != nil {
return nil, err
}
...
return blder.mgr, nil
}Surtout pour voirdoControllerEtdoWatchMéthodes:
doControllerMéthodes
func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) {
...
// Inject dependencies into Reconciler
if err := mgr.SetFields(options.Reconciler); err != nil {
return nil, err
}
// Create controller with dependencies set
return &controller.Controller{
Do: options.Reconciler,
MakeQueue: func() workqueue.RateLimitingInterface {
return workqueue.NewNamedRateLimitingQueue(options.RateLimiter, name)
},
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
CacheSyncTimeout: options.CacheSyncTimeout,
SetFields: mgr.SetFields,
Name: name,
Log: options.Log.WithName("controller").WithName(name),
}, nil
}La méthode initialise un Controller, Quelques paramètres importants sont passés :
- Do: Reconcile Logique;
- Cache:Cherche.InformerInscriptionWatch
- Queue:WatchRessourcesCUDCache d'événements
doWatchMéthodes
func (blder *Builder) doWatch() error {
// Reconcile type
typeForSrc, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
if err != nil {
return err
}
src := &source.Kind{Type: typeForSrc}
hdler := &handler.EnqueueRequestForObject{}
allPredicates := append(blder.globalPredicates, blder.forInput.predicates...)
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
return err
}
// Watches the managed types
for _, own := range blder.ownsInput {
typeForSrc, err := blder.project(own.object, own.objectProjection)
if err != nil {
return err
}
src := &source.Kind{Type: typeForSrc}
hdler := &handler.EnqueueRequestForOwner{
OwnerType: blder.forInput.object,
IsController: true,
}
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
allPredicates = append(allPredicates, own.predicates...)
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
return err
}
}
// Do the watch requests
for _, w := range blder.watchesInput {
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
allPredicates = append(allPredicates, w.predicates...)
// If the source of this watch is of type *source.Kind, project it.
if srckind, ok := w.src.(*source.Kind); ok {
typeForSrc, err := blder.project(srckind.Type, w.objectProjection)
if err != nil {
return err
}
srckind.Type = typeForSrc
}
if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil {
return err
}
}
return nil
}Vous pouvez voir la méthode à Ben ControllerResponsableCRDC'est fait.watch, Et en même temps watchBenCRD Autres ressources gérées ,C'estmanagedObjectsPeut passerControllerInitialisationBuilderDeOwnsMéthode entrée,En parlant deWatch Nous nous préoccupons de deux logiques :
1、Enregistréhandler
type EnqueueRequestForObject struct{}
// Create implements EventHandler
func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
...
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: evt.Meta.GetName(),
Namespace: evt.Meta.GetNamespace(),
}})
}
// Update implements EventHandler
func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
if evt.MetaOld != nil {
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: evt.MetaOld.GetName(),
Namespace: evt.MetaOld.GetNamespace(),
}})
} else {
enqueueLog.Error(nil, "UpdateEvent received with no old metadata", "event", evt)
}
if evt.MetaNew != nil {
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: evt.MetaNew.GetName(),
Namespace: evt.MetaNew.GetNamespace(),
}})
} else {
enqueueLog.Error(nil, "UpdateEvent received with no new metadata", "event", evt)
}
}
// Delete implements EventHandler
func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
...
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: evt.Meta.GetName(),
Namespace: evt.Meta.GetNamespace(),
}})
}Je vois.Kubebuilder Pour les Handler C'est l'objet qui va changer NamespacedNameDans la file d'attente,Si dansReconcile La logique exige un jugement pour créer /Mise à jour/Supprimer, Il faut avoir sa propre logique de jugement .
2、Processus d'inscription
// Watch implements controller.Controller
func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
...
log.Info("Starting EventSource", "controller", c.Name, "source", src)
return src.Start(evthdler, c.Queue, prct...)
}
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
// to enqueue reconcile.Requests.
func (is *Informer) Start(handler handler.EventHandler, queue workqueue.RateLimitingInterface,
...
is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
return nil
}La nôtre.Handler Inscription physique à InformerLà - haut, Pour que toute la logique s'enchaîne ,AdoptionCache Nous avons créé tous les SchemeÀ l'intérieurGVKsDeInformers,Et ça correspond.GVKDeControllerEnregistréWatch HandlerTo the correspondingInformer, Ça correspond à GVK Tout changement dans les ressources à l'intérieur déclenchera Handler, Écrivez l'événement de changement à ControllerDans la file d'attente des événements pour, Après ça, notre ReconcileMéthodes.
边栏推荐
- Chapter 9 Yunji datacanvas was rated as 36 krypton "the hard core technology enterprise most concerned by investors"
- namespace基础介绍
- Fix the problem that the highlight effect of the main menu disappears when the easycvr Video Square is clicked and played
- R language principal component PCA, factor analysis, clustering analysis of regional economy analysis of Chongqing Economic Indicators
- Master the secrets of software security testing methods, and pinch the security test report with your hands
- ESG Global Leaders Summit | Intel Wang Rui: coping with global climate challenges with the power of science and technology
- 日常工作中程序员最讨厌哪些工作事项?
- kivy教程之设置窗体大小和背景(教程含源码)
- Unit test asp Net MVC 4 Application - unit testing asp Net MVC 4 apps thoroughly
- leetcode 53. Maximum subarray maximum subarray sum (medium)
猜你喜欢

Video fusion cloud platform easycvr video Plaza left column list style optimization

The request request is encapsulated in uni app, which is easy to understand

DFS and BFS concepts and practices +acwing 842 arranged numbers (DFS) +acwing 844 Maze walking (BFS)

Basic idea of counting and sorting

1.19.11. SQL client, start SQL client, execute SQL query, environment configuration file, restart policy, user-defined functions, constructor parameters

计数排序基础思路

Intel and Xinbu technology jointly build a machine vision development kit to jointly promote the transformation of industrial intelligence

Camera calibration (I): robot hand eye calibration

DFS和BFS概念及实践+acwing 842 排列数字(dfs) +acwing 844. 走迷宫(bfs)

Why does WordPress open so slowly?
随机推荐
JetBrain Pycharm的一系列快捷键
R语言主成分pca、因子分析、聚类对地区经济研究分析重庆市经济指标
The root file system of buildreoot prompts "depmod:applt not found"
[on automation experience] the growth path of automated testing
Intel and Xinbu technology jointly build a machine vision development kit to jointly promote the transformation of industrial intelligence
Network Security Learning - Information Collection
Zero knowledge private application platform aleo (1) what is aleo
Both primary and secondary equipment numbers are 0
食堂用户菜品关系系统(C语言课设)
掌握软件安全测试方法秘笈,安全测试报告信手捏来
NTU notes 6422quiz review (1-3 sections)
sscanf,sscanf_ S and its related usage "suggested collection"
How to solve the problem of adding RTSP device to easycvr cluster version and prompting server ID error?
[untitled]
九章云极DataCanvas公司获评36氪「最受投资人关注的硬核科技企业」
GPT-3当一作自己研究自己,已投稿,在线蹲一个同行评议
这项15年前的「超前」技术设计,让CPU在AI推理中大放光彩
案例大赏:英特尔携众多合作伙伴推动多领域AI产业创新发展
Terms used in the Web3 community
用CPU方案打破内存墙?学PayPal堆傲腾扩容量,漏查欺诈交易量可降至1/30