在前面的文章当中我们已经完成了 NodePool Operator 的基本功能开发与测试,但是有时候我们会有这种需求,例如创建或者删除资源的时候需要对资源进行一些检查的操作,如果校验不成功就不通过。或者是需要在完成实际的创建之前做一些其他操作,例如我创建一个 pod 之前对 pod 的资源做一些调整等。这些都可以通过准入控制的WebHook来实现。
// Default implements webhook.Defaulter so a webhook will be registered for the type func(r *NodePool)Default() { nodepoollog.Info("default", "name", r.Name)
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. //+kubebuilder:webhook:path=/validate-nodes-lailin-xyz-v1-nodepool,mutating=false,failurePolicy=fail,sideEffects=None,groups=nodes.lailin.xyz,resources=nodepools,verbs=create;update,versions=v1,name=vnodepool.kb.io,admissionReviewVersions={v1,v1beta1}
var _ webhook.Validator = &NodePool{}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type func(r *NodePool)ValidateCreate()error { nodePoolLog.Info("validate create", "name", r.Name)
return r.validate() }
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type func(r *NodePool)ValidateUpdate(old runtime.Object)error { nodePoolLog.Info("validate update", "name", r.Name)
return r.validate() }
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type func(r *NodePool)ValidateDelete()error { nodePoolLog.Info("validate delete", "name", r.Name)
// TODO(user): fill in your validation logic upon object deletion. returnnil }
// validate 验证 func(r *NodePool)validate()error { err := errors.Errorf("taint or label key must validatedy by %s", keyReg.String())
for k := range r.Spec.Labels { if !keyReg.MatchString(k) { return errors.WithMessagef(err, "label key: %s", k) } }
for _, taint := range r.Spec.Taints { if !keyReg.MatchString(taint.Key) { return errors.WithMessagef(err, "taint key: %s", taint.Key) } }
returnnil }
部署
实现了之后直接在 make run 是跑不起来的,因为 webhook 注册的地址不对,我们这里先看一下如何进行部署运行,然后再来看如何对 WebHook 进行本地调试。
# Adds namespace to all resources. namespace:node-pool-operator-system
# Value of this field is prepended to the # names of all resources, e.g. a deployment named # "wordpress" becomes "alices-wordpress". # Note that it should also match with the prefix (text before '-') of the namespace # field above. namePrefix:node-pool-operator-
# Labels to add to all resources and selectors. #commonLabels: # someName: someValue
bases: -../crd -../rbac -../manager # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -../webhook # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. -../certmanager # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. #- ../prometheus
patchesStrategicMerge: # Protect the /metrics endpoint by putting it behind auth. # If you want your controller-manager to expose the /metrics # endpoint w/o any authn/z, please comment the following line. -manager_auth_proxy_patch.yaml
# Mount the controller config file for loading manager configurations # through a ComponentConfig type #- manager_config_patch.yaml
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in # crd/kustomization.yaml -manager_webhook_patch.yaml
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. # 'CERTMANAGER' needs to be enabled to use ca injection -webhookcainjection_patch.yaml
# the following config is for teaching kustomize how to do var substitution vars: # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -name:CERTIFICATE_NAMESPACE# namespace of the certificate CR objref: kind:Certificate group:cert-manager.io version:v1 name:serving-cert# this name should match the one in certificate.yaml fieldref: fieldpath:metadata.namespace -name:CERTIFICATE_NAME objref: kind:Certificate group:cert-manager.io version:v1 name:serving-cert# this name should match the one in certificate.yaml -name:SERVICE_NAMESPACE# namespace of the service objref: kind:Service version:v1 name:webhook-service fieldref: fieldpath:metadata.namespace -name:SERVICE_NAME objref: kind:Service version:v1 name:webhook-service
# 检查 pod 是否正常启动 ▶ kubectl -n node-pool-operator-system get pods NAME READY STATUS RESTARTS AGE node-pool-operator-controller-manager-66bd747899-lf7xb 0/2 ContainerCreating 0 7s
▶ kubectl apply -f config/samples/ Error from server (label key: xxx: taint or label key must validatedy by ^node-pool.lailin.xyz/*[a-zA-z0-9]*$): error when applying patch: {"metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"nodes.lailin.xyz/v1\",\"kind\":\"NodePool\",\"metadata\":{\"annotations\":{},\"name\":\"worker\"},\"spec\":{\"handler\":\"runc\",\"labels\":{\"xxx\":\"10\"}}}\n"}},"spec":{"labels":{"node-pool.lailin.xyz/worker":null,"xxx":"10"},"taints":null}} to: Resource: "nodes.lailin.xyz/v1, Resource=nodepools", GroupVersionKind: "nodes.lailin.xyz/v1, Kind=NodePool" Name: "worker", Namespace: "" for: "config/samples/nodes_v1_nodepool.yaml": admission webhook "vnodepool.kb.io" denied the request: label key: xxx: taint or label key must validatedy by ^node-pool.lailin.xyz/*[a-zA-z0-9]*$