前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubebuilder 学习笔记之 Webhook Server

Kubebuilder 学习笔记之 Webhook Server

原创
作者头像
blazehu
修改2022-08-12 18:15:11
1.9K0
修改2022-08-12 18:15:11
举报
文章被收录于专栏:小千世界

1. 什么是准入控制?

准入控制(Admission Controller)是 Kubernetes API Server 用于拦截请求的一种手段。Admission 可以做到对请求的资源对象进行校验,修改。service mesh 最近很火的项目 Istio 天生支持 Kubernetes,利用的就是 Admission 对服务实例自动注入 sidecar。

2. 什么是准入 Webhook?

准入 Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。 可以定义两种类型的准入 webhook,即 验证性质的准入 Webhook 和 修改性质的准入 Webhook。修改性质的准入 Webhook 会先被调用。它们可以更改发送到 API 服务器的对象以执行自定义的设置默认值操作。

在完成了所有对象修改并且 API 服务器也验证了所传入的对象之后, 验证性质的 Webhook 会被调用,并通过拒绝请求的方式来强制实施自定义的策略。

说明: 如果准入 Webhook 需要保证它们所看到的是对象的最终状态以实施某种策略。 则应使用验证性质的准入 Webhook,因为对象被修改性质 Webhook 看到之后仍然可能被修改。

image.png
image.png

3. 尝试准入 Webhook

先决条件
  • 确保 Kubernetes 集群版本至少为 v1.16(以便使用 admissionregistration.k8s.io/v1 API) 或者 v1.9 (以便使 admissionregistration.k8s.io/v1beta1 API)。
  • 确保启用 MutatingAdmissionWebhookValidatingAdmissionWebhook 控制器。 这里是一组推荐的 admission 控制器,通常可以启用。
  • 确保启用了 admissionregistration.k8s.io/v1beta1 API。

4. 配置准入 Webhook

你可以通过 ValidatingWebhookConfiguration 或者 MutatingWebhookConfiguration 动态配置哪些资源要被哪些准入 Webhook 处理。详细配置可以参阅 Webhook配置 部分。

5. 认证和信任

默认情况下,apiserver不会向webhooks进行身份验证。但是,如果您想对客户端进行身份验证,可以将apiserver配置为使用基本身份验证、承载令牌或证书对Webhook进行身份验证。你可以在这里找到详细的步骤。

6. 编写一个准入 Webhook 服务器

Webhook Admission 属于同步调用,需要用户部署自己的 webhook server,创建自定义的配置资源对象: ValidatingWebhookConfiguration 或 MutatingWebhookConfiguration。下面使用 kubebuilder 开发一个简单的 demo。

6.1 创建项目
代码语言:shell
复制
kubebuilder init --domain blazehu.com --owner "blazehu" --repo blazehu.com/kubegame

提示: 这里通过 kubebuilder v3 创建的话,在 config 目录下会缺少 certmanager、webhook 目录以及 default/manager_webhook_patch.yml 和 webhookcainjection_patch.yaml 文件。可以通过从v2生成拷贝过来进行修改。

6.2 创建控制器

这里只需要创建一个控制器

代码语言:shell
复制
kubebuilder create api --group svc --version v1 --kind App
6.3 创建 webhook
Implement Your Handler

新增 mutatingwebhook.go & validatingwebhook.go 文件

代码语言:go
复制
// mutatingwebhook.go
package controllers

import (
 "context"
 "encoding/json"
 corev1 "k8s.io/api/core/v1"
 "net/http"
 "sigs.k8s.io/controller-runtime/pkg/client"
 "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// +kubebuilder:webhook:admissionReviewVersions=v1,sideEffects=None,path=/mutate-v1-svc,mutating=true,failurePolicy=fail,groups="",resources=services,verbs=create;update,versions=v1,name=msvc.kb.io

// KubeGameAnnotator annotates Pods
type KubeGameAnnotator struct {
 Client client.Client
 decoder *admission.Decoder
}

// Handle adds an annotation to every incoming pods.
func (a *KubeGameAnnotator) Handle(ctx context.Context, req admission.Request) admission.Response {
 pod := &corev1.Pod{}

err := a.decoder.Decode(req, pod)
 if err != nil {
 return admission.Errored(http.StatusBadRequest, err)
 }

if pod.Annotations == nil {
 pod.Annotations = map[string]string{}
 }
 pod.Annotations["example-mutating-admission-webhook"] = "foo"

marshaledPod, err := json.Marshal(pod)
 if err != nil {
 return admission.Errored(http.StatusInternalServerError, err)
 }

return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
}

// KubeGameAnnotator implements admission.DecoderInjector.
// A decoder will be automatically injected.

// InjectDecoder injects the decoder.
func (a *KubeGameAnnotator) InjectDecoder(d *admission.Decoder) error {
 a.decoder = d
 return nil
}
代码语言:go
复制
// validatingwebhook.go
package controllers

import (
 "context"
 "fmt"
 corev1 "k8s.io/api/core/v1"
 "net/http"
 "sigs.k8s.io/controller-runtime/pkg/client"
 "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// +kubebuilder:webhook:admissionReviewVersions=v1,sideEffects=None,path=/validate-v1-svc,mutating=false,failurePolicy=fail,groups="",resources=services,verbs=create;update,versions=v1,name=vsvc.kb.io

// KubeGameValidator validates Pods
type KubeGameValidator struct {
 Client client.Client
 decoder *admission.Decoder
}

// Handle admits a pod if a specific annotation exists.
func (v *KubeGameValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
 pod := &corev1.Pod{}

err := v.decoder.Decode(req, pod)
 if err != nil {
 return admission.Errored(http.StatusBadRequest, err)
 }

key := "example-mutating-admission-webhook"
 anno, found := pod.Annotations[key]
 if !found {
 return admission.Denied(fmt.Sprintf("missing annotation %s", key))
 }
 if anno != "foo" {
 return admission.Denied(fmt.Sprintf("annotation %s did not have value %q", key, "foo"))
 }

return admission.Allowed("")
}

// KubeGameValidator implements admission.DecoderInjector.
// A decoder will be automatically injected.

// InjectDecoder injects the decoder.
func (v *KubeGameValidator) InjectDecoder(d *admission.Decoder) error {
 v.decoder = d
 return nil
}

注意:因为上述逻辑需要services权限,所以我们在控制器里需要添加如下内容 //+kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch;delete 用于生成 rbac manifests。

Register Your Handler

修改 main.go ,注册我们的 webhook handler

代码语言:go
复制
setupLog.Info("setting up webhook server")
hookServer := mgr.GetWebhookServer()

setupLog.Info("registering webhooks to the webhook server")
hookServer.Register("/mutate-v1-svc", &webhook.Admission{Handler: &controllers.KubeGameAnnotator{Client: mgr.GetClient()}})
hookServer.Register("/validate-v1-svc", &webhook.Admission{Handler: &controllers.KubeGameValidator{Client: mgr.GetClient()}})

提示: 这里注册的path(例如 validate-v1-sv)路径需要和 validatingwebhook.go 、mutatingwebhook.go 文件里的 CRD validation 匹配,不然 kustomize 生成出来的 webhook yaml 文件不对。

本地测试

make run 会报如下错误,是因为没有证书导致,需要配置证书,可以手动签发证书

代码语言:shell
复制
1.646924212701068e+09 ERROR setup problem running manager {"error": "open /var/folders/67/375276sx6hv0nln1whwm5syh0000gq/T/k8s-webhook-server/serving-certs/tls.crt: no such file or directory"}

我本地指定证书目录:

代码语言:go
复制
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 Scheme: scheme,
 MetricsBindAddress: metricsAddr,
 Port: 9443,
 HealthProbeBindAddress: probeAddr,
 LeaderElection: enableLeaderElection,
 LeaderElectionID: "27e1b0af.blazehu.com",
 CertDir: "./cert/",
 })

重新启动发现恢复正常

image.png
image.png

提示: run controller-gen rbac:roleName=manager-role crd webhook paths=./... output:crd:artifacts:config=config/crd/bases -w to see all available markers, or controller-gen rbac:roleName=manager-role crd webhook paths=./... output:crd:artifacts:config=config/crd/bases -h for usage

7. 部署至集群

7.1 部署 cert manager

建议使用 certmanager 为 webhook 服务器提供证书。其他解决方案也有效,只要它们将证书放在所需的位置。安装文档点这里

通过如下方式注入 caBundle :

代码语言:yaml
复制
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
 name: mutating-webhook-configuration
 annotations:
 cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
 name: validating-webhook-configuration
 annotations:
 cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
7.2 构建镜像
  • 镜像替换:default/manager_auth_proxy_patch.yaml 文件中的 gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 (网络慢)
  • Dockerfile 去掉 go mod download,直接使用本地 vendor 构建 (网络慢)
  • Dockerfile 去掉 COPY api/ api/, 因为没有创建 Resource
  • 去掉 main.go 文件中配置的证书路径
代码语言:shell
复制
make docker-build IMG=xxxx
make docker-push IMG=xxxx
7.3 修改模版,然后部署
  • 修改 config/default/kustomization.yaml , 将 webhook、certmanager 相关的注释去掉。
  • 修改 config/crd/kustomization.yaml ,将 webhook、certmanager 相关的注释去掉。
  • 修改 config/default/kustomization.yaml , 将 crd 相关的给注释掉。
代码语言:shell
复制
make deploy IMG=xxxx

部署成功:

image.png
image.png

查看控制器日志:

image.png
image.png
7.4 测试

简单创建一个 service,webhook 会注入一个注解,并进行验证。下图可以看到成功注入。

image.png
image.png

控制日志:

image.png
image.png

说明:查看 MutatingWebhookConfiguration 配置可以看到 caBundle 被注入其中了。

8. 总结

总结下 webhook Admission 的优势:

  • webhook 可动态扩展 Admission 能力,满足自定义客户的需求。
  • 不需要重启 API Server,可通过创建 webhook configuration 热加载 webhook admission。

参考文档

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 什么是准入控制?
  • 2. 什么是准入 Webhook?
  • 3. 尝试准入 Webhook
    • 先决条件
    • 4. 配置准入 Webhook
    • 5. 认证和信任
    • 6. 编写一个准入 Webhook 服务器
      • 6.1 创建项目
        • 6.2 创建控制器
          • 6.3 创建 webhook
            • Implement Your Handler
            • Register Your Handler
          • 本地测试
          • 7. 部署至集群
            • 7.1 部署 cert manager
              • 7.2 构建镜像
                • 7.3 修改模版,然后部署
                  • 7.4 测试
                  • 8. 总结
                  • 参考文档
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档