簡介
之前介紹過controller-runtime總覽sigs.k8s.io controller-runtime總覽 ,
本文主要介紹pkg/builder的原始碼分析,
目錄結構
-
builder_suite_test.go 校驗k8s環境 獲取client config
- 依賴ginkgo做集成測驗,表示該檔案夾內的測驗例執行之前執行,
- BeforeSuite和AfterSuite,會在所有測驗例執行之前和之后執行
- 如果BeforeSuite執行失敗,則這個測驗集都不會被執行
-
controller.go
- Builder結構體 構建controller所需要的引數
type Builder struct { forInput ForInput //封裝實作了runtime.Object的結構體 ownsInput []OwnsInput // 封裝了apiType的owner,用于EnqueueRequestForOwner使用 watchesInput []WatchesInput // 封裝type和evenHandler,一般使用owns和For代替,如果想擴展,可以使用 mgr manager.Manager // mgr 主要使用內部的引數構造controller globalPredicates []predicate.Predicate // 全域過濾事件 ctrl controller.Controller // 構造的controller ctrlOptions controller.Options // 構造的controller 的引數包括最大并發reconcile數和reconciler name string //默認是對應apiType的小寫形式,符合普羅米修斯的命名格式 }- ControllerManagedBy函式 根據提供的mgr生成一個新的builder
func ControllerManagedBy(m manager.Manager) *Builder { return &Builder{mgr: m} }- ForInput結構體 作為For方法的入參 (reconcile的object)
type ForInput struct { object client.Object //封裝實作了runtime.Object的結構體 predicates []predicate.Predicate //過濾事件 objectProjection objectProjection //標識我們可以發送/接收一個給定的resource(metadata-only, unstructured, etc) err error }- blder For方法 新建forInput,設定forInput的predicates并給blder的forInput賦值
func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder { if blder.forInput.object != nil { blder.forInput.err = fmt.Errorf("For(...) should only be called once, could not assign multiple objects for reconciliation") return blder } input := ForInput{object: object} for _, opt := range opts { opt.ApplyToFor(&input) } blder.forInput = input return blder }- OwnsInput結構體 作為Owns方法的入參 (ForInput的owner的object)
type OwnsInput struct { object client.Object //封裝實作了runtime.Object的結構體 predicates []predicate.Predicate //過濾事件 objectProjection objectProjection //標識我們可以發送/接收一個給定的resource(metadata-only, unstructured, etc) } - blder Owns方法 給blder的ownsInput追加物件,具體看blder.ownsInput的作用
func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder { input := OwnsInput{object: object} for _, opt := range opts { opt.ApplyToOwns(&input) } blder.ownsInput = append(blder.ownsInput, input) return blder }- watchRequest結構體 封裝watch物件和事件處理器
type watchRequest struct { src source.Source eventhandler handler.EventHandler predicates []predicate.Predicate objectProjection objectProjection }- blder Watches方法 給blder.watchesInput追加WatchesInput
func (blder *Builder) Watches(src source.Source, eventhandler handler.EventHandler, opts ...WatchesOption) *Builder { input := WatchesInput{src: src, eventhandler: eventhandler} for _, opt := range opts { opt.ApplyToWatches(&input) } blder.watchesInput = append(blder.watchesInput, input) return blder }- blder WithOptions方法 設定controller的Options
- blder WithLogger方法 設定controller的Options.Log
- blder WithEventFilter方法 給blder.globalPredicates追加過濾事件物件
func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder { blder.globalPredicates = append(blder.globalPredicates, p) return blder }- blder Named方法 給blder.name賦值
- blder Complete方法 注意了 ,這個是核心方法,根據提供的reconciler生成blder.ctrl開啟ctrl.watch
func (blder *Builder) Complete(r reconcile.Reconciler) error { //呼叫Build _, err := blder.Build(r) return err } func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, error) { if r == nil { return nil, fmt.Errorf("must provide a non-nil Reconciler") } if blder.mgr == nil { return nil, fmt.Errorf("must provide a non-nil Manager") } if blder.forInput.err != nil { return nil, blder.forInput.err } // 校驗要reconcile的物件是否存在 if blder.forInput.object == nil { return nil, fmt.Errorf("must provide an object for reconciliation") } // 創建controller賦值給blder.ctrl if err := blder.doController(r); err != nil { return nil, err } // 開啟ctrl.watch(包括owner和apiType) if err := blder.doWatch(); err != nil { return nil, err } return blder.ctrl, nil } func (blder *Builder) doWatch() error { // Reconcile 對應的apitype 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 } // 監聽owns對應的type 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 } } // 監聽watchs對應的source 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 } func (blder *Builder) doController(r reconcile.Reconciler) error { // 獲取全域的opts globalOpts := blder.mgr.GetControllerOptions() // 獲取controller的opts ctrlOptions := blder.ctrlOptions // 設定reconciler if ctrlOptions.Reconciler == nil { ctrlOptions.Reconciler = r } // 重新獲取我們將要 reconciling的GVK gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme()) if err != nil { return err } // 設定最大并發Reconcile的數目 if ctrlOptions.MaxConcurrentReconciles == 0 { groupKind := gvk.GroupKind().String() // 如果獲取當前的reconcile數大于0,就設定為當前的 if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 { ctrlOptions.MaxConcurrentReconciles = concurrency } } // 設定cache同步過期時間 if ctrlOptions.CacheSyncTimeout == 0 && globalOpts.CacheSyncTimeout != nil { ctrlOptions.CacheSyncTimeout = *globalOpts.CacheSyncTimeout } // 設定controller的log if ctrlOptions.Log == nil { ctrlOptions.Log = blder.mgr.GetLogger() } ctrlOptions.Log = ctrlOptions.Log.WithValues("reconciler group", gvk.Group, "reconciler kind", gvk.Kind) //構造controller 呼叫pkg/controller的New方法 blder.ctrl, err = newController(blder.getControllerName(gvk), blder.mgr, ctrlOptions) return err } -
controller_test.go 測驗操作builder的檔案
-
doc.go 提供一個log
-
example_test.go 基于ReplicaSet的測驗例子
-
example_webhook_test.go 此示例使用Webhook構建器創建一個簡單的Webhook,該Webhook由CRD ChaosPod的mgr進行管理,
-
options.go 為controller提供設定Option的檔案(設定Predicates和objectProjection)
-
webhook.go
- WebhookBuilder結構體 構建webhook所需要的引數
type WebhookBuilder struct { apiType runtime.Object // 鉤子觸發的apiType(實作了runtime.Object的結構體) gvk schema.GroupVersionKind // 鉤子觸發的apiType的gvk mgr manager.Manager // mgr提供構建webhook所需的屬性 config *rest.Config // k8s的client配置 }- WebhookManagedBy函式 根據提供的mgr生成一個新的webhookBuilder
func WebhookManagedBy(m manager.Manager) *WebhookBuilder { return &WebhookBuilder{mgr: m} }- blder For方法 給blder的apiType賦值
func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder { blder.apiType = apiType return blder }- blder Complete方法 注意了 ,這個是核心方法,為apiType對應的GVK注冊DefaultingWebhook(改變)、ValidatingWebhook(驗證)和ConversionWebhook(version轉換)
func (blder *WebhookBuilder) Complete() error { // 加載client config blder.loadRestConfig() // 注冊需要的webhook return blder.registerWebhooks() } func (blder *WebhookBuilder) registerWebhooks() error { // 獲取gvk var err error blder.gvk, err = apiutil.GVKForObject(blder.apiType, blder.mgr.GetScheme()) if err != nil { return err } // 注冊mutaing webhook blder.registerDefaultingWebhook() // 注冊validate webhook blder.registerValidatingWebhook() // 注冊conversion webhook err = blder.registerConversionWebhook() if err != nil { return err } return nil } func (blder *WebhookBuilder) registerDefaultingWebhook() { //型別轉換 defaulter, isDefaulter := blder.apiType.(admission.Defaulter) if !isDefaulter { log.Info("skip registering a mutating webhook, admission.Defaulter interface is not implemented", "GVK", blder.gvk) return } //根據default validate使用pkg/admission獲取mutaing webhook mwh := admission.DefaultingWebhookFor(defaulter) if mwh != nil { // 生成mutate path path := generateMutatePath(blder.gvk) // 校驗該path是否已經注冊 // 如果true,跳過 if !blder.isAlreadyHandled(path) { log.Info("Registering a mutating webhook", "GVK", blder.gvk, "path", path) blder.mgr.GetWebhookServer().Register(path, mwh) } } } func (blder *WebhookBuilder) registerValidatingWebhook() { validator, isValidator := blder.apiType.(admission.Validator) if !isValidator { log.Info("skip registering a validating webhook, admission.Validator interface is not implemented", "GVK", blder.gvk) return } vwh := admission.ValidatingWebhookFor(validator) if vwh != nil { path := generateValidatePath(blder.gvk) // Checking if the path is already registered. // If so, just skip it. if !blder.isAlreadyHandled(path) { log.Info("Registering a validating webhook", "GVK", blder.gvk, "path", path) blder.mgr.GetWebhookServer().Register(path, vwh) } } } func (blder *WebhookBuilder) registerConversionWebhook() error { ok, err := conversion.IsConvertible(blder.mgr.GetScheme(), blder.apiType) if err != nil { log.Error(err, "conversion check failed", "object", blder.apiType) return err } if ok { if !blder.isAlreadyHandled("/convert") { blder.mgr.GetWebhookServer().Register("/convert", &conversion.Webhook{}) } log.Info("conversion webhook enabled", "object", blder.apiType) } return nil } //判斷path是否已經注冊過 func (blder *WebhookBuilder) isAlreadyHandled(path string) bool { if blder.mgr.GetWebhookServer().WebhookMux == nil { return false } h, p := blder.mgr.GetWebhookServer().WebhookMux.Handler(&http.Request{URL: &url.URL{Path: path}}) if p == path && h != nil { return true } return false } //生成mutate path func generateMutatePath(gvk schema.GroupVersionKind) string { return "/mutate-" + strings.Replace(gvk.Group, ".", "-", -1) + "-" + gvk.Version + "-" + strings.ToLower(gvk.Kind) } //生成validate path func generateValidatePath(gvk schema.GroupVersionKind) string { return "/validate-" + strings.Replace(gvk.Group, ".", "-", -1) + "-" + gvk.Version + "-" + strings.ToLower(gvk.Kind) } -
webhook_test.go 鉤子測驗檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/276990.html
標籤:其他
