开发K8s准入控制器前的准备工作:集群检查与项目搭建指南
前言在上一篇文章中我们规划了要开发一个自动注入Nginx Sidecar的Webhook。但在真正开始写代码之前必须先做好充分的准备工作。我曾经踩过一个坑代码写完了部署到集群却发现apiserver根本没有启用MutatingAdmissionWebhook插件导致Webhook完全不生效。回过来检查配置、重新编译apiserver浪费了大量时间。今天就详细讲讲开发K8s准入控制器前的准备工作包括集群环境检查、项目初始化、配置设计等。第一步检查集群准入配置1.1 检查Admission Registration API首先确认集群是否启用了准入控制的APIkubectl api-versions|grepadmission期望的输出admissionregistration.k8s.io/v1 admissionregistration.k8s.io/v1beta1说明v1是稳定版本Kubernetes 1.16v1beta1是旧版本建议用v1如果没有输出说明集群版本太旧1.9不支持Webhook1.2 检查准入控制插件确认apiserver启用了MutatingAdmissionWebhook和ValidatingAdmissionWebhook# 方法1查看apiserver进程参数psaux|grepkube-apiserver|grepenable-admission-plugins# 方法2如果是静态Podkubectl get pod-nkube-system-lcomponentkube-apiserver-oyaml|grepenable-admission-plugins# 方法3查看kube-apiserver帮助如果在本地有apiserver二进制文件kube-apiserver-h|grepenable-admission-pluginsKubernetes 1.20默认启用的插件NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota关键插件✅MutatingAdmissionWebhook必须启用用于Mutating Webhook✅ValidatingAdmissionWebhook必须启用用于Validating Webhook如果发现没有启用# 修改apiserver启动参数kube-apiserver\--enable-admission-plugins...,MutatingAdmissionWebhook,ValidatingAdmissionWebhook# 如果是kubeadm部署的集群修改/etc/kubernetes/manifests/kube-apiserver.yaml1.3 测试Webhook连通性可以先创建一个简单的测试Webhook验证环境# 创建一个简单的nginx服务模拟Webhookkubectl create deployment webhook-test--imagenginx kubectl expose deployment webhook-test--port443--target-port443# 检查是否可以访问kubectl get svc webhook-test第二步创建Go项目2.1 初始化项目# 创建项目目录mkdir-p~/projects/kube-mutating-webhook-inject-podcd~/projects/kube-mutating-webhook-inject-pod# 初始化Go模块go mod init kube-mutating-webhook-inject-pod# 创建项目结构mkdir-ppkg deploy certs2.2 添加依赖# 添加K8s API依赖go get k8s.io/apilatest go get k8s.io/apimachinerylatest# 添加YAML解析依赖go get gopkg.in/yaml.v2# 添加日志依赖可选也可以用标准库go get github.com/golang/glog# 整理依赖go mod tidy生成的go.mod文件module kube-mutating-webhook-inject-podgo1.21require(github.com/golang/glog v1.2.0gopkg.in/yaml.v2 v2.4.0k8s.io/api v0.28.0k8s.io/apimachinery v0.28.0)第三步设计配置结构3.1 配置文件设计我们需要一个配置文件定义要注入的Sidecar容器。复用K8s原生的Container和Volume结构# config.yamlcontainers:-name:sidecar-nginximage:nginx:1.25-alpineimagePullPolicy:IfNotPresentports:-containerPort:80protocol:TCPvolumeMounts:-name:nginx-confmountPath:/etc/nginx/conf.dresources:limits:cpu:100mmemory:128Mirequests:cpu:50mmemory:64Mivolumes:-name:nginx-confconfigMap:name:nginx-sidecar-config设计说明containers要注入的sidecar容器列表可以注入多个volumessidecar需要的volume使用K8s原生结构便于验证和使用3.2 Go结构体定义// pkg/config.gopackagemainimport(corev1k8s.io/api/core/v1)// Config 存储注入配置typeConfigstruct{Containers[]corev1.Containeryaml:containers// 要注入的容器Volumes[]corev1.Volumeyaml:volumes// 要注入的volume}3.3 配置加载函数// pkg/config.goimport(crypto/sha256fmtio/ioutilgithub.com/golang/gloggopkg.in/yaml.v2)// loadConfig 从文件加载配置funcloadConfig(configFilestring)(*Config,error){// 读取配置文件data,err:ioutil.ReadFile(configFile)iferr!nil{returnnil,fmt.Errorf(failed to read config file: %w,err)}// 计算配置文件的hash便于调试glog.Infof(New configuration: sha256sum %x,sha256.Sum256(data))// 解析YAMLvarcfg Configiferr:yaml.Unmarshal(data,cfg);err!nil{returnnil,fmt.Errorf(failed to parse config: %w,err)}returncfg,nil}第四步搭建HTTPS服务器Webhook必须使用HTTPSKubernetes要求所以我们需要TLS证书后续会生成HTTPS服务器4.1 Webhook配置结构// pkg/webhook.gopackagemainimport(net/http)// webhookServer Webhook服务器typewebhookServerstruct{sidecarConfig*Config// 注入配置server*http.Server// HTTP服务器}4.2 命令行参数// main.gopackagemainimport(flagfmtgithub.com/golang/glog)// webHookSvrOptions Webhook服务器选项typewebHookSvrOptionsstruct{portint// HTTPS监听端口certFilestring// TLS证书文件路径keyFilestring// TLS私钥文件路径sidecarCfgFilestring// Sidecar配置文件路径}funcmain(){varrunOption webHookSvrOptions// 解析命令行参数flag.IntVar(runOption.port,port,8443,Webhook server port.)flag.StringVar(runOption.certFile,tlsCertFile,/etc/webhook/certs/cert.pem,File containing the x509 Certificate for HTTPS.)flag.StringVar(runOption.keyFile,tlsKeyFile,/etc/webhook/certs/key.pem,File containing the x509 private key to --tlsCertFile.)flag.StringVar(runOption.sidecarCfgFile,sidecarCfgFile,config.yaml,File containing the mutation configuration.)flag.Parse()// 加载配置sidecarConfig,err:loadConfig(runOption.sidecarCfgFile)iferr!nil{glog.Errorf(Failed to load configuration: %v,err)return}glog.Infof([sidecarConfig:%v],sidecarConfig)}4.3 加载TLS证书// main.goimport(crypto/tls)funcmain(){// ... 加载配置 ...// 加载TLS证书对pair,err:tls.LoadX509KeyPair(runOption.certFile,runOption.keyFile)iferr!nil{glog.Errorf(Failed to load key pair: %v,err)return}glog.Infof(Loaded TLS certificate successfully)}4.4 创建HTTPS服务器// main.goimport(fmtnet/http)funcmain(){// ... 加载配置和证书 ...// 创建Webhook服务器实例webhooksvr:webhookServer{sidecarConfig:sidecarConfig,server:http.Server{Addr:fmt.Sprintf(:%v,runOption.port),TLSConfig:tls.Config{Certificates:[]tls.Certificate{pair},},},}// 创建路由mux:http.NewServeMux()mux.HandleFunc(/mutate,webhooksvr.serveMutate)mux.HandleFunc(/health,webhooksvr.serveHealth)webhooksvr.server.Handlermux glog.Infof(Starting webhook server on port %d,runOption.port)// 在goroutine中启动服务器gofunc(){// 注意ListenAndServeTLS的第一个参数为空字符串使用server.Addriferr:webhooksvr.server.ListenAndServeTLS(,);err!nil{glog.Errorf(Failed to listen and serve webhook server: %v,err)}}()}4.5 添加Handler// pkg/webhook.goimport(ionet/httpgithub.com/golang/glog)// serveMutate 处理/mutate请求func(ws*webhookServer)serveMutate(w http.ResponseWriter,r*http.Request){// 读取请求体body,err:io.ReadAll(r.Body)iferr!nil{http.Error(w,fmt.Sprintf(could not read request body: %v,err),http.StatusBadRequest)return}glog.Infof(Received mutation request: %s,string(body))// TODO: 解析AdmissionReview构造响应// 这部分在下一篇文章中详细讲解}// serveHealth 健康检查func(ws*webhookServer)serveHealth(w http.ResponseWriter,r*http.Request){w.WriteHeader(http.StatusOK)w.Write([]byte(ok))}4.6 优雅关闭// main.goimport(contextosos/signalsyscall)funcmain(){// ... 启动服务器 ...// 监听系统信号实现优雅关闭signalChan:make(chanos.Signal,1)signal.Notify(signalChan,syscall.SIGINT,syscall.SIGTERM)// 等待信号-signalChan glog.Infof(Got OS shutdown signal, shutting down webhook server gracefully...)// 优雅关闭服务器ctx,cancel:context.WithTimeout(context.Background(),10*time.Second)defercancel()iferr:webhooksvr.server.Shutdown(ctx);err!nil{glog.Errorf(Server shutdown error: %v,err)}}第五步本地测试准备5.1 创建测试证书临时在正式部署前可以用自签名证书本地测试# 生成私钥openssl genrsa-outcerts/server.key2048# 生成证书签名请求openssl req-new-keycerts/server.key-outcerts/server.csr\-subj/CNlocalhost/OTest# 生成自签名证书openssl x509-req-days365-incerts/server.csr\-signkeycerts/server.key-outcerts/server.crt5.2 创建测试配置# test-config.yamlcontainers:-name:sidecar-nginximage:nginx:alpineports:-containerPort:80volumes:[]5.3 本地运行测试# 编译go build-owebhook-server.# 运行使用测试证书./webhook-server\--port8443\--tlsCertFilecerts/server.crt\--tlsKeyFilecerts/server.key\--sidecarCfgFiletest-config.yaml# 测试健康检查curl-khttps://localhost:8443/health# 输出: ok第六步容器化准备6.1 Dockerfile# Dockerfile FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED0 GOOSlinux go build -o webhook-server . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR / COPY --frombuilder /app/webhook-server /webhook-server # 创建证书和配置目录 RUN mkdir -p /etc/webhook/certs /etc/webhook/config EXPOSE 8443 ENTRYPOINT [/webhook-server]6.2 构建镜像# 构建dockerbuild-tnginx-sidecar-injector:v1.0.# 测试运行dockerrun-d\-p8443:8443\-v$(pwd)/certs:/etc/webhook/certs\-v$(pwd)/test-config.yaml:/etc/webhook/config/config.yaml\nginx-sidecar-injector:v1.0\--sidecarCfgFile/etc/webhook/config/config.yaml准备工作清单在开始写核心业务逻辑前确保完成了以下检查集群启用了admissionregistration.k8s.io/v1API集群启用了MutatingAdmissionWebhook和ValidatingAdmissionWebhook插件创建了Go项目并初始化了模块设计了配置文件结构和加载逻辑搭建了基本的HTTPS服务器框架实现了配置加载功能实现了健康检查接口创建了Dockerfile用于容器化本地测试可以正常运行常见问题排查问题1kubectl api-versions没有admissionregistration原因集群版本太旧1.9解决升级Kubernetes版本问题2加载证书失败Failed to load key pair: open /etc/webhook/certs/cert.pem: no such file or directory原因证书路径错误或证书不存在解决# 检查证书文件是否存在ls-lacerts/# 确保路径正确./webhook-server--tlsCertFile./certs/server.crt--tlsKeyFile./certs/server.key问题3端口被占用Failed to listen and serve webhook server: listen :8443: bind: address already in use解决# 查找占用端口的进程lsof-i:8443# 杀掉进程或更换端口./webhook-server--port8444问题4配置文件解析失败Failed to load configuration: failed to parse config: yaml: unmarshal errors原因YAML格式错误解决使用YAML验证工具检查配置文件总结完成准备工作后项目结构应该是kube-mutating-webhook-inject-pod/ ├── go.mod ├── go.sum ├── main.go # 主程序入口 ├── config.yaml # 配置文件 ├── pkg/ │ └── webhook.go # Webhook逻辑待实现 ├── certs/ # 证书目录 │ ├── server.crt │ └── server.key ├── deploy/ # 部署文件待创建 └── Dockerfile现在基础框架已经搭建好了下一篇文章我们将实现核心的Mutation逻辑——解析AdmissionReview、构造JSON Patch、返回响应。下一步准备好环境后就可以开始实现核心的Webhook逻辑了解析AdmissionReview请求构造Pod Patch返回AdmissionResponse部署到K8s集群你准备好了吗你的集群启用了MutatingAdmissionWebhook吗你是如何管理项目依赖的Go Modules还是其他工具你在搭建HTTPS服务器时遇到过什么问题求助与交流如果你在准备工作中遇到了问题欢迎在评论区交流。

相关新闻

多场景低压配电母线槽应用方案,适配高安全标准电气工程

多场景低压配电母线槽应用方案,适配高安全标准电气工程

随着国内工业升级、大型基建、商住配套工程不断增加,不同场景对低压主干配电设备的安全、负载、环境适配要求分化明显。母线槽凭借载流量大、布线简洁、运维便捷的优势,逐步替代传统电缆桥架,成为大型电气工程主流配电方案。本文结合多行业配…

2026/6/20 22:05:27阅读更多 →
ComfyUI-Impact-Pack Switch节点兼容性问题:从故障诊断到高效修复指南

ComfyUI-Impact-Pack Switch节点兼容性问题:从故障诊断到高效修复指南

ComfyUI-Impact-Pack Switch节点兼容性问题:从故障诊断到高效修复指南 【免费下载链接】ComfyUI-Impact-Pack Custom nodes pack for ComfyUI This custom node helps to conveniently enhance images through Detector, Detailer, Upscaler, Pipe, and more. 项目…

2026/6/20 22:05:27阅读更多 →
大数据转大模型:把关键流程跑顺

大数据转大模型:把关键流程跑顺

《大数据转大模型:把关键流程跑顺》看起来是个大话题,但真落到项目里,常常就是几个具体选择。下面我尽量按实际开发时会遇到的问题来讲。摘要本文概述文章目标、核心观点和实践价值。[摘要] 从 Hadoop/Spark 生态切到大模型工程,很…

2026/6/20 22:00:26阅读更多 →
LeRobot终极指南:如何用开源AI框架构建智能机器人控制系统

LeRobot终极指南:如何用开源AI框架构建智能机器人控制系统

LeRobot终极指南:如何用开源AI框架构建智能机器人控制系统 【免费下载链接】lerobot 🤗 LeRobot: Making AI for Robotics more accessible with end-to-end learning 项目地址: https://gitcode.com/GitHub_Trending/le/lerobot LeRobot是一个专…

2026/6/20 23:35:37阅读更多 →
从OneNote到Markdown:3步实现笔记无缝迁移的完整指南

从OneNote到Markdown:3步实现笔记无缝迁移的完整指南

从OneNote到Markdown:3步实现笔记无缝迁移的完整指南 【免费下载链接】onenote-md-exporter ConsoleApp to export OneNote notebooks to Markdown formats 项目地址: https://gitcode.com/gh_mirrors/on/onenote-md-exporter onenote-md-exporter是一款专为…

2026/6/20 23:35:37阅读更多 →
3步快速免费解锁网盘高速下载:本地化直链解析解决方案

3步快速免费解锁网盘高速下载:本地化直链解析解决方案

3步快速免费解锁网盘高速下载:本地化直链解析解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

2026/6/20 23:35:37阅读更多 →
如何快速配置PS2文件管理器:终极启动工具完整指南

如何快速配置PS2文件管理器:终极启动工具完整指南

如何快速配置PS2文件管理器:终极启动工具完整指南 【免费下载链接】wLaunchELF ELF loader and File browser for Sony PlayStation 2 项目地址: https://gitcode.com/gh_mirrors/wl/wLaunchELF wLaunchELF是索尼PlayStation 2游戏机的开源文件管理器与ELF启…

2026/6/20 23:35:37阅读更多 →
free-domains未来展望:路线图规划与社区发展计划

free-domains未来展望:路线图规划与社区发展计划

free-domains未来展望:路线图规划与社区发展计划 【免费下载链接】free-domains 🌐 DNS configuration for some of my domains 项目地址: https://gitcode.com/gh_mirrors/fr/free-domains free-domains是一个以代码形式管理域名DNS记录的开源项…

2026/6/20 23:35:37阅读更多 →
终极指南:如何用VisualCppRedist AIO一键解决Windows所有VC++运行库问题

终极指南:如何用VisualCppRedist AIO一键解决Windows所有VC++运行库问题

终极指南:如何用VisualCppRedist AIO一键解决Windows所有VC运行库问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 在Windows系统开发和软件部署领…

2026/6/20 23:30:36阅读更多 →
【课程设计/毕业设计】基于 Web 的高校县志馆藏信息综合管理系统设计与实现 基于Django的青岛滨海学院特色文献捐赠流转管理系统的设计与实现【附源码、数据库、万字文档】

【课程设计/毕业设计】基于 Web 的高校县志馆藏信息综合管理系统设计与实现 基于Django的青岛滨海学院特色文献捐赠流转管理系统的设计与实现【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/6/20 0:02:40阅读更多 →
MC68HC908RF2A定时器PWM生成原理与实战:无缓冲与缓冲模式详解

MC68HC908RF2A定时器PWM生成原理与实战:无缓冲与缓冲模式详解

1. 项目概述与核心价值在嵌入式开发,尤其是电机驱动、LED调光、开关电源这些需要精确控制“能量”的领域,脉冲宽度调制(PWM)技术是工程师手中的一把瑞士军刀。它的本质很简单:用一个固定频率的方波,通过改变…

2026/6/20 0:02:40阅读更多 →
在银河麒麟V10桌面(2205版本)上实战部署软RAID 1:从模块黑名单到自动挂载

在银河麒麟V10桌面(2205版本)上实战部署软RAID 1:从模块黑名单到自动挂载

1. 银河麒麟V10桌面系统与软RAID 1基础认知 第一次在银河麒麟V10桌面上折腾软RAID 1时,我踩了不少坑。这个国产操作系统基于Linux内核,但2205版本对软RAID模块做了特殊处理,需要额外操作才能正常使用。软RAID 1其实就是磁盘镜像技术&#xff…

2026/6/20 0:02:40阅读更多 →