kubebuilder构建一个你的Webhook
准入控制器简介
在编写Webhook之前,我们得知道准入控制器是干嘛的~
准入控制器 它会在请求通过认证和鉴权之后、对象被持久化之前 拦截到达 API 服务器的请求。 准入控制器可以执行验证(Validating
) 和/或变更(Mutating
) 操作。 变更(mutating
)控制器可以根据被其接受的请求更改相关对象;验证(validating)控制器则不行。
准入控制器限制创建、删除、修改对象的请求。 准入控制器也可以阻止自定义动作,例如通过 API 服务器代理连接到 Pod 的请求。 准入控制器不会 (也不能)阻止读取(get 、watch 或 list)对象的请求。
-
DefaultIngressClass
-
DefaultStorageClass
-
OwnerReferencesPermissionEnforcement
-
PersistentVolumeClaimResize
-
ServiceAccount
-
ValidatingAdmissionWebhook:此准入控制器调用与请求匹配的所有验证性 Webhook。 匹配的 Webhook 将被并行调用。如果其中任何一个拒绝请求,则整个请求将失败。
-
MutatingAdmissionWebhook:
MutatingAdmissionWebhook
,顾名思义,仅在变更阶段运行。此准入控制器调用任何与请求匹配的变更(Mutating) Webhook。匹配的 Webhook 将被顺序调用。 每一个 Webhook 都可以自由修改对象。
Webhook快速实践
准入 Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。 可以定义两种类型的准入 Webhook, 即验证性质的准入 ValidatingAdmissionWebhook 和变更性质的准入 MutatingAdmissionWebhook。
当 Kubernetes 接收到新的或更新的资源对象时,MutatingAdmissionWebhook 会首先被调用,允许对资源对象进行修改。然后,ValidatingAdmissionWebhook 被调用,用于对修改后的资源对象进行验证和校验,确保其符合所定义的规则和要求。
创建ValidatingAdmissionWebhook
承接上篇,我们创建一个webhook
bash
# conversion webhook
kubebuilder create webhook --group app --version v1 --kind Webservice --defaulting --programmatic-validation
--conversion if set, scaffold the conversion webhook 转换
--defaulting if set, scaffold the defaulting webhook 预设
--programmatic-validation if set, scaffold the validating webhook 验证
# 创建 MutatingAdmissionWebhook
# kubebuilder create webhook --group app --version v1 --kind Webservice --conversion
修改api/v1/webservice_webhook.go,我们找到// TODO(user)
的地方,来写我们自己的逻辑,例如我们定义Replicas必须大于1
go
func (r *Webservice) Default() {
webservicelog.Info("default", "name", r.Name)
// TODO(user): fill in your defaulting logic.
// 校验Replicas必须大于1,如果Replicas小于等于1,则设置Replicas为2
if r.Spec.Replicas <= 1 && r.Spec.Replicas != 0 {
r.Spec.Replicas = 2
}
}
在 app.webservice-operator.163.com/v1
版本下的 webservices
资源create;update;delete的时候调用webhook
go
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
//+kubebuilder:webhook:path=/validate-app-webservice-operator-163-com-v1-webservice,mutating=false,failurePolicy=fail,sideEffects=None,groups=app.webservice-operator.163.com,resources=webservices,verbs=create;update,versions=v1,name=vwebservice.kb.io,admissionReviewVersions=v1
ValidateCreate
、ValidateUpdate
和ValidateDelete
方法将分别在创建、更新和删除时进行验证。我们也可以在里面定义自己的逻辑
go
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r *Webservice) ValidateCreate() error {
webservicelog.Info("validate create", "name", r.Name)
// TODO(user): fill in your validation logic upon object creation.
return nil
}
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (r *Webservice) ValidateUpdate(old runtime.Object) error {
webservicelog.Info("validate update", "name", r.Name)
// TODO(user): fill in your validation logic upon object update.
return nil
}
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (r *Webservice) ValidateDelete() error {
webservicelog.Info("validate delete", "name", r.Name)
// TODO(user): fill in your validation logic upon object deletion.
return nil
}
部署
和operator一样的,我们需要生成CR或CRD等清单和安装CRD
shell
# 生成CR或CRD等清单
make manifests
# 安装CRD
make install
如果webhook在kubernetes环境之外运行,需要生成对应的证书放在所在环境,默认地址是:/tmp/k8s-webhook-server/serving-certs/tls.{crt,key}
。
我们一般使用cert-manager-webhook为我们的webhook服务器自动配置证书,直接把服务部署到集群进行验证,但是在部署的时候一定要注意影响,因为失败会拦截请求。
shell
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
# 验证部署
$ kubectl get pod -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-7865d8497c-z9hqz 1/1 Running 0 5m22s
cert-manager-cainjector-7769cd8976-hdv28 1/1 Running 0 5m22s
cert-manager-webhook-7768cfb496-n8dnx 1/1 Running 0 5m22s
$ kubectl get ValidatingWebhookConfiguration cert-manager-webhook -oyaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
annotations:
cert-manager.io/inject-ca-from-secret: cert-manager/cert-manager-webhook-ca
$ kubectl get MutatingWebhookConfiguration cert-manager-webhook -oyaml
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
annotations:
cert-manager.io/inject-ca-from-secret: cert-manager/cert-manager-webhook-ca
编辑config/default/kustomization.yaml
,带WEBHOOK
、CERTMANAGER
的都取消注释即可
yaml
bases:
- ../crd
- ../rbac
- ../manager
- ../webhook
- ../certmanager
patchesStrategicMerge:
- manager_auth_proxy_patch.yaml
- manager_webhook_patch.yaml
- webhookcainjection_patch.yaml
vars:
- 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
编辑config/crd/kustomization.yaml
go
patchesStrategicMerge:
- patches/webhook_in_webservices.yaml
- patches/cainjection_in_webservices.yaml
构建镜像,推送到仓库中
shell
$ make docker-build docker-push IMG=xxx/webserviceshook:v1
部署
shell
$ make deploy IMG=xxx/webserviceshook:v1
namespace/operator-demo-system created
customresourcedefinition.apiextensions.k8s.io/webservices.app.webservice-operator.163.com created
serviceaccount/operator-demo-controller-manager created
role.rbac.authorization.k8s.io/operator-demo-leader-election-role created
clusterrole.rbac.authorization.k8s.io/operator-demo-manager-role created
clusterrole.rbac.authorization.k8s.io/operator-demo-metrics-reader created
clusterrole.rbac.authorization.k8s.io/operator-demo-proxy-role created
rolebinding.rbac.authorization.k8s.io/operator-demo-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/operator-demo-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/operator-demo-proxy-rolebinding created
service/operator-demo-controller-manager-metrics-service created
service/operator-demo-webhook-service created
deployment.apps/operator-demo-controller-manager created
certificate.cert-manager.io/operator-demo-serving-cert created
issuer.cert-manager.io/operator-demo-selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/operator-demo-mutating-webhook-configuration created
validatingwebhookconfiguration.admissionregistration.k8s.io/operator-demo-validating-webhook-configuration created
$ kubectl get po -n operator-demo-system
NAME READY STATUS RESTARTS AGE
operator-demo-controller-manager-86ff9b7bb-lg4wl 2/2 Running 0 60s
验证
测试我们的逻辑是否正常运行
shell
# 我们设置replicas: 1,逻辑就是我们不允许1个副本
$ kubectl apply -f config/samples/app_v1_webservice.yaml
webservice.app.webservice-operator.163.com/webservice-sample created
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
webservice-sample 2/2 2 2 3m58s # 成功修改成2
如果遇到一个提示x509证书问题
shell
$ kubectl apply -f config/samples/app_v1_webservice.yaml
Error from server (InternalError): error when creating "config/samples/app_v1_webservice.yaml": Internal error occurred: failed calling webhook "mwebservice.kb.io": failed to call webhook: Post "https://operator-demo-webhook-service.operator-demo-system.svc:443/mutate-app-webservice-operator-163-com-v1-webservice?timeout=10s": x509: certificate signed by unknown authority
# 我们验证secret有没有创建出来,创建出来了大多是cert-manager的问题,解决方法是重新部署cert-manager,并且检查代码config下的相关注释有没有放开
$ kubectl get secret -n operator-demo-system webhook-server-cert
NAME TYPE DATA AGE
webhook-server-cert kubernetes.io/tls 3 8m2s
到此我们对kubebuilder的使用算是有了初步的了解。