前言
上一篇 client-go 实现准入 webhook 讲的是直接用 client-go 去编写 webhook server. 这篇将讲述如何使用 controller-runtime 快速的写一个 webhook server.
编写 webhook server
这次是直接用 controller-runtime 的 webhook, 自己写一个 handle 处理逻辑就好了,所以实现起来也是比 client-go 版本更加简单明了。下面贴出主要处理逻辑,完整代码可参考 validating handler.
// ValidatingHandler validates deployment,scale
type ValidatingHandler struct {
Client client.Client
decoder *admission.Decoder
serviceName string
}
func NewValidatingHandler(c client.Client, servicename string) *ValidatingHandler {
return &ValidatingHandler{
Client: c,
serviceName: servicename,
}
}
func (vh *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
switch req.Kind.Kind {
case deploymentKind:
isAllow := false
if isAllow {
return admission.Allowed("")
}
return admission.Denied(fmt.Sprintf("The %s service doesn't allow update", req.Name))
case scaleKind:
isAllow := false
if isAllow {
return admission.Allowed("")
}
return admission.Denied(fmt.Sprintf("The %s service doesn't allow update", req.Name))
}
return admission.Allowed("")
}
// InjectDecoder injects the decoder.
func (vh *ValidatingHandler) InjectDecoder(d *admission.Decoder) error {
vh.decoder = d
return nil
}
然后 你就可以直接在 main 函数中像下面这个调用即可。完整代码请参考 main.go.
mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{
Port: *webhookServerPort,
CertDir: *certPath,
})
if err != nil {
panic(err.Error())
}
hookServer := mgr.GetWebhookServer()
hookServer.Register("/validate", &webhook.Admission{
Handler: webhookserver.NewValidatingHandler(mgr.GetClient(), *serviceName),
})
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
panic(err.Error())
}
}
编译代码并重新生成 docker image
可以参考我提供的简单 build.sh 脚本编译代码和使用 buildimage.sh 脚本去构建 docker 镜像。
NOTE: buildimage.sh 脚本中,我做了些处理,首先需要传入 docker_user(如果你没有,你也可以随意指定一个即可)和构建的 image 的 tag。然后我注释掉了 docker push 这个命令,防止有些读者还没有 docker hub 或其他仓库的账号。
添加相应的 k8s 资源
安装相应的 k8s 资源即可,具体请参考 resources.
NOTE: 这里我为了方便管理这些资源,我使用了 helm 去管理了,如果你有 helm 相关的环境,你可直接使用 helm install
命令安装资源,如果你没有或者不熟悉,你可以使用 kubectl apply
命令一个个的部署,但是你需要修改资源中的 Release.Namespace 到你安装的那个 namespace 下,例如如果你安装时没有指定 namespace, 则默认是 default。
测试
例子中 default 的实现是拒绝任何对 deployment 和 scale 的修改。所以可以使用 kubectl edit 命令修改 deployment,或者使用 kubectl scale 命令修改 replicas。如果命令修改失败并提示"The %s service doesn’t allow update",则说明自定义的 validating webhook 是可以工作的。然后可以加上自己的处理逻辑即可。