当前位置:网站首页>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.
边栏推荐
- Zhou Yajin, a top safety scholar of Zhejiang University, is a curiosity driven activist
- 日常工作中程序员最讨厌哪些工作事项?
- How to solve the problem of adding RTSP device to easycvr cluster version and prompting server ID error?
- 軟件測試之網站測試如何進行?測試小攻略走起!
- Network Security Learning - Information Collection
- What about the collapse of win11 playing pubg? Solution to win11 Jedi survival crash
- Chapter 9 Yunji datacanvas was rated as 36 krypton "the hard core technology enterprise most concerned by investors"
- 浙江大学周亚金:“又破又立”的顶尖安全学者,好奇心驱动的行动派
- SQL where multiple field filtering
- 计数排序基础思路
猜你喜欢
Lessons and thoughts of the first SQL injection
Easycvr cannot be played using webrtc. How to solve it?
1.19.11. SQL client, start SQL client, execute SQL query, environment configuration file, restart policy, user-defined functions, constructor parameters
Digital chemical plants realize the coexistence of advantages of high quality, low cost and fast efficiency
How to open win11 remote desktop connection? Five methods of win11 Remote Desktop Connection
The easycvr platform is connected to the RTMP protocol, and the interface call prompts how to solve the error of obtaining video recording?
【线段树实战】最近的请求次数 + 区域和检索 - 数组可修改+我的日程安排表Ⅰ/Ⅲ
Chapter 9 Yunji datacanvas company has been ranked top 3 in China's machine learning platform market
Win11图片打不开怎么办?Win11无法打开图片的修复方法
EasyCVR视频广场点击播放时,主菜单高亮效果消失问题的修复
随机推荐
Complimentary tickets quick grab | industry bigwigs talk about the quality and efficiency of software qecon conference is coming
EasyCVR集群版本添加RTSP设备提示服务器ID错误,该如何解决?
Jetson nano configures pytorch deep learning environment / / to be improved
Master the secrets of software security testing methods, and pinch the security test report with your hands
Web3 社区中使用的术语
Zhou Yajin, a top safety scholar of Zhejiang University, is a curiosity driven activist
【实践出真理】import和require的引入方式真的和网上说的一样吗
Code source de la fonction [analogique numérique] MATLAB allcycles () (non disponible avant 2021a)
微信能开小号了,拼多多“砍一刀”被判侵权,字节VR设备出货量全球第二,今日更多大新闻在此
Some understandings about 01 backpacker
A series of shortcut keys for jetbrain pychar
B站大佬用我的世界搞出卷积神经网络,LeCun转发!爆肝6个月,播放破百万
组织实战攻防演练的5个阶段
Unit test asp Net MVC 4 Application - unit testing asp Net MVC 4 apps thoroughly
What if win11 pictures cannot be opened? Repair method of win11 unable to open pictures
leetcode 53. Maximum Subarray 最大子数组和(中等)
leetcode 53. Maximum subarray maximum subarray sum (medium)
深入解析Kubebuilder
Optimization of channel status offline of other server devices caused by easycvr cluster restart
Lecture 3 of "prime mover x cloud native positive sounding, cost reduction and efficiency enhancement lecture" - kubernetes cluster utilization improvement practice