当前位置:网站首页>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.
边栏推荐
- [line segment tree practice] recent requests + area and retrieval - array modifiable + my schedule I / III
- What if the win11 screenshot key cannot be used? Solution to the failure of win11 screenshot key
- [team learning] [34 issues] scratch (Level 2)
- In depth analysis of kubebuilder
- 食堂用户菜品关系系统(C语言课设)
- 深耕开发者生态,加速AI产业创新发展 英特尔携众多合作伙伴共聚
- C # use Siemens S7 protocol to read and write PLC DB block
- How to solve the problem of adding RTSP device to easycvr cluster version and prompting server ID error?
- 掌握软件安全测试方法秘笈,安全测试报告信手捏来
- How to conduct website testing of software testing? Test strategy let's go!
猜你喜欢

九章云极DataCanvas公司摘获「第五届数字金融创新大赛」最高荣誉!
![[line segment tree practice] recent requests + area and retrieval - array modifiable + my schedule I / III](/img/13/d598bb53b71fbadd4a97c603152124.png)
[line segment tree practice] recent requests + area and retrieval - array modifiable + my schedule I / III

The easycvr platform is connected to the RTMP protocol, and the interface call prompts how to solve the error of obtaining video recording?

acwing 843. n-皇后问题

AI landing new question type RPA + AI =?

Chapter 9 Yunji datacanvas company won the highest honor of the "fifth digital finance innovation competition"!

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

How do test / development programmers get promoted? From nothing, from thin to thick

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

namespace基础介绍
随机推荐
Digital chemical plants realize the coexistence of advantages of high quality, low cost and fast efficiency
这项15年前的「超前」技术设计,让CPU在AI推理中大放光彩
How to conduct website testing of software testing? Test strategy let's go!
Depth first traversal template principle of tree and graph
On the 110th anniversary of Turing's birth, has the prediction of intelligent machine come true?
leetcode 53. Maximum Subarray 最大子数组和(中等)
窗口可不是什么便宜的东西
Chapter 9 Yunji datacanvas company has been ranked top 3 in China's machine learning platform market
Complimentary tickets quick grab | industry bigwigs talk about the quality and efficiency of software qecon conference is coming
Jetson nano配置pytorch深度学习环境//待完善
Wechat can play the trumpet. Pinduoduo was found guilty of infringement. The shipment of byte VR equipment ranks second in the world. Today, more big news is here
Deeply cultivate the developer ecosystem, accelerate the innovation and development of AI industry, and Intel brings many partners together
Terms used in the Web3 community
两个div在同一行,两个div不换行「建议收藏」
Chapter 9 Yunji datacanvas company won the highest honor of the "fifth digital finance innovation competition"!
[untitled]
【数模】Matlab allcycles()函数的源代码(2021a之前版本没有)
EasyCVR集群版本添加RTSP设备提示服务器ID错误,该如何解决?
The easycvr platform is connected to the RTMP protocol, and the interface call prompts how to solve the error of obtaining video recording?
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?