基于kube-builder实现kubernetes webhook实践总结
背景
kubebuilder对webhook的支持主要基于同样用kubebuilder构建的CRD,而对于非kubebuilder项目内构建的类型,还是需要一些work around来实现webhook的构建。
项目内CRD
对于kubebuilder项目生成的CRD,如果想加入一些默认值webhook、校验webhook等,可以很方便的根据官方文档来完成:Implementing defaulting/validating webhooks - The Kubebuilder Book
但是本文的重点不在于此。
非项目内CRD
本文将以kubevirt的vm crd为例,建立webhook。
官方文档对这种情况有基本的指导:Webhooks for Core Types - The Kubebuilder Book,不过还是缺少step by step的指南。
step by step guide
代码框架
- 创建kubebuilder项目:
kubebuilder init --domain mec.io --repo mec-daemon
- 根据官方文档,构建结构体,实现
admission.Handler
接口 - 加webhook和rbac标记
- 加构造函数,在main.go里注册webhook
镜像构建
- 生成自签名的https证书
- 修改dockerfile:将自签证书放到镜像里kubebuilder webhook的默认位置
COPY --chown=65532 tls* /tmp/k8s-webhook-server/serving-certs/
- 修改Makefile里的IMG
- 尝试使用
make docker-build
构建镜像。由于我们没有使用kubebuilder的api和controller功能,中间可能遇到缺失目录的错误,按照错误提示修改dockerfile解决即可 - 至此我们的webhook核心代码和镜像部分完成
集群部署
- kubebuilder的默认部署逻辑基于make和kustomize完成,同样由于我们没有用到api和controller功能,所以需要一些定制修改
- 修改
config/default/kustomization.yaml
:修改bases节点,选择需要部署的yaml模块。只保留rbac、manager和webhook模块 - 注释掉
manager_auth_proxy_patch.yaml
,否则会有kube-rbac-proxy容器,增加了复杂度 - 修改
config/manager/manager.yaml
:手写一个service - 注释掉
config/rbac/kustomization.yaml
中和auth_proxy相关的yaml - 默认生成的时候没有给webhook生成kustomization文件,参照其他模块,在
config/webhook
中创建一个kustomization - 默认使用
make manifes
生成的MutatingWebhookConfiguration中不包含自签证书的caBundle字段,查文档没找到kubebuilder标记里怎么加,所以修改makefile,在make manifests结束后将证书读进来,加入到MutatingWebhookConfiguration相应的位置 make deploy
测试部署
验证
创建一个vm,查看webhook日志
总结:证书问题
k8s webhook的实现中,有了controller-runtime和kubebuilder的封装,核心代码的编写其实已经比较容易。但是难点出现在了部署时的证书方案上。由于k8s要求必须启用https且无法跳过证书认证环节,所以证书的问题难以绕过。总结起来,大致有几种方案实现证书的管理:
- kubebuilder官方支持的基于cert-manager管理证书。弊端是比较复杂,需要引入额外的组件和生态,可能webhook逻辑非常简单,但是却花了大量时间研究cert-manager相关的生态。且kubebuilder本身的文档也没有这块的step by step教程。
- 使用自签证书,并设置超长的有效期,然后固定封装到镜像中。同时配置到MutatingWebhookConfiguration中,使k8s能够信任自签证书。方案优势:一劳永逸,相比1来说学习成本低。弊端:安全性低,不符合证书设计的初衷。
- k8s中本身也大量使用了证书机制,最近版本的集群中也支持了用集群ca签发可信的证书。所以如果没有多集群部署的需求,可以生成csr等证书配置,直接用k8s的根证书签发证书。该方案也可用于开发调试阶段。
- 上一个方案有手动的因素,且无法跨集群自动完成,在搜索引擎上搜索,看到了另一种方案,是对上一方案的自动化:kubernetes 之 admission webhook生成证书 (cuisongliu.github.io),将签发证书的流程用go实现,并结合client-go存储在集群中。
- 进一步,可以将4的方案做成一个init-container,在webhook启动前完成证书的签发、注入和配置。
参考
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。