当前位置: 首页 > news >正文

开发K8s准入控制器前的准备工作:集群检查与项目搭建指南

前言

在上一篇文章中,我们规划了要开发一个自动注入Nginx Sidecar的Webhook。但在真正开始写代码之前,必须先做好充分的准备工作。

我曾经踩过一个坑:代码写完了,部署到集群却发现apiserver根本没有启用MutatingAdmissionWebhook插件,导致Webhook完全不生效。回过来检查配置、重新编译apiserver,浪费了大量时间。

今天就详细讲讲开发K8s准入控制器前的准备工作,包括集群环境检查、项目初始化、配置设计等。

第一步:检查集群准入配置

1.1 检查Admission Registration API

首先确认集群是否启用了准入控制的API:

kubectl api-versions|grepadmission

期望的输出:

admissionregistration.k8s.io/v1 admissionregistration.k8s.io/v1beta1

说明

  • v1是稳定版本(Kubernetes 1.16+)
  • v1beta1是旧版本,建议用v1
  • 如果没有输出,说明集群版本太旧(<1.9),不支持Webhook

1.2 检查准入控制插件

确认apiserver启用了MutatingAdmissionWebhookValidatingAdmissionWebhook

# 方法1:查看apiserver进程参数psaux|grepkube-apiserver|grepenable-admission-plugins# 方法2:如果是静态Podkubectl get pod-nkube-system-lcomponent=kube-apiserver-oyaml|grepenable-admission-plugins# 方法3:查看kube-apiserver帮助(如果在本地有apiserver二进制文件)kube-apiserver-h|grepenable-admission-plugins

Kubernetes 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.yaml

1.3 测试Webhook连通性

可以先创建一个简单的测试Webhook验证环境:

# 创建一个简单的nginx服务模拟Webhookkubectl create deployment webhook-test--image=nginx kubectl expose deployment webhook-test--port=443--target-port=443# 检查是否可以访问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 certs

2.2 添加依赖

# 添加K8s API依赖go get k8s.io/api@latest go get k8s.io/apimachinery@latest# 添加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容器列表(可以注入多个)
  • volumes:sidecar需要的volume
  • 使用K8s原生结构,便于验证和使用

3.2 Go结构体定义

// pkg/config.gopackagemainimport(corev1"k8s.io/api/core/v1")// Config 存储注入配置typeConfigstruct{Containers[]corev1.Container`yaml:"containers"`// 要注入的容器Volumes[]corev1.Volume`yaml:"volumes"`// 要注入的volume}

3.3 配置加载函数

// pkg/config.goimport("crypto/sha256""fmt""io/ioutil""github.com/golang/glog""gopkg.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)}return&cfg,nil}

第四步:搭建HTTPS服务器

Webhook必须使用HTTPS(Kubernetes要求),所以我们需要:

  1. TLS证书(后续会生成)
  2. HTTPS服务器

4.1 Webhook配置结构

// pkg/webhook.gopackagemainimport("net/http")// webhookServer Webhook服务器typewebhookServerstruct{sidecarConfig*Config// 注入配置server*http.Server// HTTP服务器}

4.2 命令行参数

// main.gopackagemainimport("flag""fmt""github.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("fmt""net/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.Handler=mux 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("io""net/http""github.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("context""os""os/signal""syscall")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"/CN=localhost/O=Test"# 生成自签名证书openssl x509-req-days365-incerts/server.csr\-signkeycerts/server.key-outcerts/server.crt

5.2 创建测试配置

# test-config.yamlcontainers:-name:sidecar-nginximage:nginx:alpineports:-containerPort:80volumes:[]

5.3 本地运行测试

# 编译go build-owebhook-server.# 运行(使用测试证书)./webhook-server\--port=8443\--tlsCertFile=certs/server.crt\--tlsKeyFile=certs/server.key\--sidecarCfgFile=test-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_ENABLED=0 GOOS=linux go build -o webhook-server . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR / COPY --from=builder /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
  • 集群启用了MutatingAdmissionWebhookValidatingAdmissionWebhook插件
  • 创建了Go项目并初始化了模块
  • 设计了配置文件结构和加载逻辑
  • 搭建了基本的HTTPS服务器框架
  • 实现了配置加载功能
  • 实现了健康检查接口
  • 创建了Dockerfile用于容器化
  • 本地测试可以正常运行

常见问题排查

问题1:kubectl 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--port=8444

问题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逻辑了:

  1. 解析AdmissionReview请求
  2. 构造Pod Patch
  3. 返回AdmissionResponse
  4. 部署到K8s集群

你准备好了吗?

  1. 你的集群启用了MutatingAdmissionWebhook吗?
  2. 你是如何管理项目依赖的?Go Modules还是其他工具?
  3. 你在搭建HTTPS服务器时遇到过什么问题?

求助与交流

如果你在准备工作中遇到了问题,欢迎在评论区交流。

http://www.jsqmd.com/news/1050965/

相关文章:

  • 如何高效使用开源网盘直链下载助手:专业用户的实战指南
  • 合肥理工学校 2026 招生什么条件?2026年6月21号最新公布! - 教育为先
  • 终极指南:5步免费绕过iOS 15-16激活锁,解锁你的iPhone/iPad设备
  • 鸿蒙应用开发中的单位详解:px、vp、fp、lpx
  • 做税务体检怕踩坑?广州中小企业服务筛选全攻略 - 资讯速览
  • 2026年南阳市PMP培训机构哪家好?官方授权R.E.P.报考指南 - 众智商学院课程中心
  • 终极免费解决方案:如何用novideo_srgb轻松校准NVIDIA显卡广色域显示器色彩
  • STM32F103C8 + FreeRTOS + ESP32 学习记录(一):从零搭建联网天气时钟站(硬件篇)
  • 2026 GEO 优化公司推荐:4A 广告公司【舜风传媒】领衔 GEO 全案服务商 - GrowthUME
  • Android Studio中文界面插件:让开发工具说你的母语
  • 2026年常州货架厂口碑排行,这几家值得推荐 - 官方资讯
  • 2026南昌靠谱黄金回收门店推荐:金诚高价透明无套路,专业技术避坑全解析 - 资讯速览
  • 靠谱营业性演出许可证代办机构推荐 - 资讯速览
  • 2026 年合肥高科经济技工学校招生简章|报名方式、招生专业、录取条件详解 - 教育为先
  • 想找好用的长沙全屋定制公司?这里给你揭晓答案! - 资讯速览
  • 抖音公会选择核心标准 - 资讯速览
  • 2026代办营业性演出许可证机构推荐哪家好 - 资讯速览
  • GPT Pro + Codex:开发者到底能提升多少效率?
  • 黄山学院应届生的平均薪资大概是多少?优势专业的薪资水平更高吗? - 寻茫精选
  • 自动驾驶PPO训练实战:从Mujoco到CARLA的闭环落地
  • 2026年EVA泡棉、硅胶制品、保护膜、双面胶、绒布垫厂家精选指南:品类齐全与品控稳定兼具的胶粘制品供应商选择指南 - 海棠依旧大
  • Google Veo API调用实战:从REST接口到视频生成工程化
  • 5分钟快速部署Nginx反向代理中文管理面板:终极可视化配置指南
  • 黄山学院毕业生考公、考编的比例高吗?学校有没有相关的备考指导? - 寻茫精选
  • 2026 定制开发一套 ERP 系统大概多少钱?一文理清企业所有隐性支出 - 资讯速览
  • 合肥中专推荐哪家好?首选合肥理工学校! - 教育为先
  • 嵌入式GUI开发:emWin树形视图控件核心API与实战应用
  • (开源)MotorEffMAP-电机电控效率MAP图绘制程序
  • 2026常州货架厂推荐榜:这5家企业实力领先同行 - 官方资讯
  • 上货前必做!抖店违规检测怎么操作?免费工具+周期避坑指南 - 抖掌柜