开发一个MutatingWebhook

大号在练葵花宝典  金牌会员 | 2024-8-22 14:28:19 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 554|帖子 554|积分 1662

介绍

Webhook就是一种HTTP回调,用于在某种环境下执行某些动作,Webhook不是K8S独有的,很多场景下都可以进行Webhook,比如在提交完代码后调用一个Webhook自动构建docker镜像
准入 Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。 可以界说两种类型的准入 Webhook, 即验证性质的准入 Webhook 和变更性质的准入 Webhook。 变更性质的准入 Webhook 会先被调用。它们可以修改发送到 API 服务器的对象以执行自界说的设置默认值操纵。
在完成了所有对象修改并且 API 服务器也验证了所传入的对象之后, 验证性质的 Webhook 会被调用,并通过拒绝请求的方式来强制实施自界说的战略。
Admission Webhook使用较多的场景如下

  • 在资源持久化到ETCD之进步行修改(Mutating Webhook),比如增加init Container大概sidecar Container
  • 在资源持久化到ETCD之进步行校验(Validating Webhook),不满足条件的资源直接拒绝并给出相应信息
组成

  • webhook 服务
  • webhook 配置
  • webhook 证书
创建核心组件Pod的Webhook

使用kubebuilder新建webhook项目
  1. kubebuilder init --domain test.com --repo gitlab.qima-inc.com/test-operator
复制代码
  1. (base) (⎈ |kubernetes-admin@qa-u03:qa)➜  test-operator kubebuilder init --domain test.com --repo gitlab.qima-inc.com/test-operator
  2. INFO Writing kustomize manifests for you to edit...
  3. INFO Writing scaffold for you to edit...
  4. INFO Get controller runtime:
  5. $ go get sigs.k8s.io/controller-runtime@v0.17.2
  6. INFO Update dependencies:
  7. $ go mod tidy
  8. go: go.mod file indicates go 1.21, but maximum version supported by tidy is 1.19
  9. Error: failed to initialize project: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v4": exit status 1
复制代码
因为我默认是是go1.19所以版本达不到要求,这里两种处理方式

  • 指定 --plugins go/v3 --project-version 3
  • 切换高版本golang 这里我切换了go1.22
  1. (base) (⎈ |kubernetes-admin@qa-u03:qa)➜  test-operator kubebuilder init --domain test.com --repo gitlab.qima-inc.com/test-operator                                    
  2. INFO Writing kustomize manifests for you to edit...
  3. INFO Writing scaffold for you to edit...         
  4. INFO Get controller runtime:
  5. $ go get sigs.k8s.io/controller-runtime@v0.17.2
  6. INFO Update dependencies:
  7. $ go mod tidy           
  8. Next: define a resource with:
  9. $ kubebuilder create api
复制代码
生成核心组件Pod的API
  1. (base) (⎈ |kubernetes-admin@qa-u03:qa)➜  test-operator kubebuilder create api --group core --version v1 --kind Pod                                                   
  2. INFO Create Resource [y/n]                        
  3. n
  4. INFO Create Controller [y/n]                     
  5. n
  6. INFO Writing kustomize manifests for you to edit...
  7. INFO Writing scaffold for you to edit...         
  8. INFO Update dependencies:
  9. $ go mod tidy        
复制代码
这里有两个选项,创建资源和创建控制器
因为是内置资源Pod所以不必要创建资源,也不必要控制器
假如是自界说资源,必要创建资源,创建控制器
创建webhook
  1. (base) (⎈ |kubernetes-admin@qa-u03:qa)➜  test-operator kubebuilder create webhook --group core --version v1 --kind Pod --defaulting --programmatic-validation
  2. INFO Writing kustomize manifests for you to edit...
  3. ERRO Unable to find the target(s) #- path: patches/webhook/* to uncomment in the file config/crd/kustomization.yaml.
  4. ERRO Unable to find the target(s) #configurations:
  5. #- kustomizeconfig.yaml to uncomment in the file config/crd/kustomization.yaml.
  6. INFO Writing scaffold for you to edit...         
  7. INFO api/v1/pod_webhook.go                        
  8. INFO api/v1/pod_webhook_test.go                  
  9. INFO api/v1/webhook_suite_test.go                 
  10. INFO Update dependencies:
  11. $ go mod tidy           
  12. INFO Running make:
  13. $ make generate               
  14. mkdir -p /Users/xxxx/test-operator/bin
  15. Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0
  16. /Users/xxxx/test-operator/bin/controller-gen-v0.14.0 object:headerFile="hack/boilerplate.go.txt" paths="./..."
  17. Next: implement your new Webhook and generate the manifests with:
  18. $ make manifests
复制代码
代码结构
  1. .
  2. ├── Dockerfile
  3. ├── Makefile
  4. ├── PROJECT
  5. ├── README.md
  6. ├── api
  7. │   └── v1
  8. │       ├── pod_webhook.go
  9. │       ├── pod_webhook_test.go
  10. │       └── webhook_suite_test.go
  11. ├── bin
  12. │   └── controller-gen-v0.14.0
  13. ├── cmd
  14. │   └── main.go
  15. ├── config
  16. │   ├── certmanager
  17. │   │   ├── certificate.yaml
  18. │   │   ├── kustomization.yaml
  19. │   │   └── kustomizeconfig.yaml
  20. │   ├── crd
  21. │   │   └── patches
  22. │   │       ├── cainjection_in_pods.yaml
  23. │   │       └── webhook_in_pods.yaml
  24. │   ├── default
  25. │   │   ├── kustomization.yaml
  26. │   │   ├── manager_auth_proxy_patch.yaml
  27. │   │   ├── manager_config_patch.yaml
  28. │   │   ├── manager_webhook_patch.yaml
  29. │   │   └── webhookcainjection_patch.yaml
  30. │   ├── manager
  31. │   │   ├── kustomization.yaml
  32. │   │   └── manager.yaml
  33. │   ├── prometheus
  34. │   │   ├── kustomization.yaml
  35. │   │   └── monitor.yaml
  36. │   ├── rbac
  37. │   │   ├── auth_proxy_client_clusterrole.yaml
  38. │   │   ├── auth_proxy_role.yaml
  39. │   │   ├── auth_proxy_role_binding.yaml
  40. │   │   ├── auth_proxy_service.yaml
  41. │   │   ├── kustomization.yaml
  42. │   │   ├── leader_election_role.yaml
  43. │   │   ├── leader_election_role_binding.yaml
  44. │   │   ├── role.yaml
  45. │   │   ├── role_binding.yaml
  46. │   │   └── service_account.yaml
  47. │   └── webhook
  48. │       ├── kustomization.yaml
  49. │       ├── kustomizeconfig.yaml
  50. │       ├── manifests.yaml
  51. │       └── service.yaml
  52. ├── go.mod
  53. ├── go.sum
  54. ├── hack
  55. │   └── boilerplate.go.txt
  56. └── test
  57. ├── e2e
  58. │   ├── e2e_suite_test.go
  59. │   └── e2e_test.go
  60. └── utils
  61. └── utils.go
复制代码
实现Webhook相关代码

因为只有Webhook,没有Controller 所以只必要实现Webhook相关代码即可,同时必要解释掉一些代码如:
Dockerfile中的
  1. # COPY internal/controller/ internal/controller/
复制代码
修改api/v1/xxx_suite_test.go
因为核心组件Pod的Webhook和一般的CRD的webhook不一样,此处生成的pod_webhook.go只有Default()这个function,因此,我们必要直接重写整个代码,最重要的是Handle()方法。
  1. /*
  2. Copyright 2024.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6.     http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package v1
  14. import (
  15.         "fmt"
  16.         "net/http"
  17.         "sigs.k8s.io/controller-runtime/pkg/client"
  18.         logf "sigs.k8s.io/controller-runtime/pkg/log"
  19.         "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
  20. )
  21. // log is for logging in this package.
  22. var podlog = logf.Log.WithName("pod-resource")
  23. // 定义核心组件pod的webhook的主struct,类似于java的Class
  24. type PodWebhookMutate struct {
  25.         Client  client.Client
  26.         decoder *admission.Decoder
  27. }
  28. // +kubebuilder:webhook:path=/mutate-core-v1-pod,mutating=true,failurePolicy=fail,sideEffects=None,groups=core,resources=pods,verbs=create;update,versions=v1,name=mpod.kb.io,admissionReviewVersions=v1
  29. func (a *PodWebhookMutate) Handle(ctx context.Context, req admission.Request) admission.Response {
  30.         pod := &corev1.Pod{}
  31.         err := a.decoder.Decode(req, pod)
  32.         if err != nil {
  33.                 return admission.Errored(http.StatusBadRequest, err)
  34.         }
  35.         // TODO: 变量marshaledPod是一个Map,可以直接修改pod的一些属性
  36.         marshaledPod, err := json.Marshal(pod)
  37.         if err != nil {
  38.                 return admission.Errored(http.StatusInternalServerError, err)
  39.         }
  40.         // 打印
  41.         fmt.Println("======================================================")
  42.         fmt.Println(string(marshaledPod))
  43.         return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
  44. }
  45. func (a *PodWebhookMutate) InjectDecoder(d *admission.Decoder) error {
  46.         a.decoder = d
  47.         return nil
  48. }
复制代码
修改main.go文件:
  1. if os.Getenv("ENABLE_WEBHOOKS") != "false" {
  2.     //if err = (&corev1.Pod{}).SetupWebhookWithManager(mgr); err != nil {
  3.     //        setupLog.Error(err, "unable to create webhook", "webhook", "Pod")
  4.     //        os.Exit(1)
  5.     //}
  6.     mgr.GetWebhookServer().Register("/mutate-core-v1-pod", &webhook.Admission{Handler: &v1.PodWebhookMutate{Client: mgr.GetClient()}})
  7. }
复制代码
生成mainfests
  1. make manifests generate
复制代码
证书

手动签发证书

https://cuisongliu.github.io/2020/07/kubernetes/admission-webhook/
自动签发证书

webhook 服务启动时自动生成证书,授权证书

  • 创建CA根证书以及服务的证书
  • 将服务端、CA证书写入 k8s Secret,并且支持find or create
  • 当地写入证书
  • 获取MutatingWebhookConfiguration和ValidatingWebhookConfiguration将caCert写入webhook config中的ClientConfig.CABundle(这里有个问题是webhook必要提前创建,CABundle可以写个临时值,等webhook server 启动覆盖)
自动签发证书参考项目: https://github.com/koordinator-sh/koordinator/blob/main/pkg/webhook/util/controller/webhook_controller.go#L187

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大号在练葵花宝典

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表