当前位置:网站首页>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.
边栏推荐
- The root file system of buildreoot prompts "depmod:applt not found"
- System framework of PureMVC
- EasyCVR平台接入RTMP协议,接口调用提示获取录像错误该如何解决?
- Zero knowledge private application platform aleo (1) what is aleo
- How does vscade use the built-in browser?
- sscanf,sscanf_s及其相关使用方法「建议收藏」
- DFS和BFS概念及实践+acwing 842 排列数字(dfs) +acwing 844. 走迷宫(bfs)
- Up to 5million per person per year! Choose people instead of projects, focus on basic scientific research, and scientists dominate the "new cornerstone" funded by Tencent to start the application
- Terms used in the Web3 community
- Win11玩绝地求生(PUBG)崩溃怎么办?Win11玩绝地求生崩溃解决方法
猜你喜欢

深入解析Kubebuilder

Kivy tutorial of setting the size and background of the form (tutorial includes source code)

Vscode 如何使用内置浏览器?

用CPU方案打破内存墙?学PayPal堆傲腾扩容量,漏查欺诈交易量可降至1/30

What if win11 pictures cannot be opened? Repair method of win11 unable to open pictures

Win11玩绝地求生(PUBG)崩溃怎么办?Win11玩绝地求生崩溃解决方法

Have you got the same "artifact" of cross architecture development praised by various industry leaders?

R语言主成分pca、因子分析、聚类对地区经济研究分析重庆市经济指标

AI 落地新题型 RPA + AI =?

窗口可不是什么便宜的东西
随机推荐
软件测试之网站测试如何进行?测试小攻略走起!
抖音或将推出独立种草社区平台:会不会成为第二个小红书
Why does WordPress open so slowly?
leetcode 53. Maximum Subarray 最大子数组和(中等)
Web3 社区中使用的术语
MySQL null value processing and value replacement
Advertising attribution: how to measure the value of buying volume?
掌握软件安全测试方法秘笈,安全测试报告信手捏来
Chapter 9 Yunji datacanvas was rated as 36 krypton "the hard core technology enterprise most concerned by investors"
[team learning] [34 sessions] Alibaba cloud Tianchi online programming training camp
leetcode 53. Maximum Subarray 最大子数组和(中等)
You can't sell the used lithography machine to China! The United States unreasonably pressured the Dutch ASML, and domestic chips were suppressed again
Chapter 9 Yunji datacanvas company has been ranked top 3 in China's machine learning platform market
Fiance donated 500million dollars to female PI, so that she didn't need to apply for projects, recruited 150 scientists, and did scientific research at ease!
ESG全球领导者峰会|英特尔王锐:以科技之力应对全球气候挑战
Organize five stages of actual attack and defense drill
Jetson nano配置pytorch深度学习环境//待完善
Introduction to namespace Basics
Is there any way to bookmark the code in the visual studio project- Is there a way to bookmark code in a Visual Studio project?
深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚