
minikube Addon 开发完全指南从零创建、注册到提交一个全新的 Addon【免费下载链接】minikubeRun Kubernetes locally项目地址: https://gitcode.com/gh_mirrors/mi/minikube导读本文基于 minikube 官方贡献文档系统讲解如何为 minikube 开发一个全新的 Addon插件从 fork 仓库、编写 Kubernetes 清单文件到通过//go:embed嵌入资源、注册到pkg/addons/config.go、接入minikube addons list与minikube addons open再到本地测试与提交 PR 的完整流程。文中所有步骤均与当前仓库源码一一对应读者学完后可以独立完成一个 Addon 的端到端开发与合入并理解 addon 在启动、启用、禁用时的底层运行机制。一、Addon 机制概述一个 Addon 在 minikube 中是如何存在的minikube 的 Addon 本质上是一组 Kubernetes 清单manifest它们被打包进 minikube 二进制文件在用户执行minikube addons enable name时被拷贝进虚拟机或容器并应用apply到集群中。一个 Addon 从源码到运行要经过三个层次的登记缺一不可层次文件作用清单文件deploy/addons/ /存放该 Addon 的所有 YAML /.tmpl模板资源嵌入deploy/addons/assets.go通过//go:embed把清单编译进二进制注册表pkg/minikube/assets/addons.go声明每个 Addon 要拷贝哪些文件、目标路径、权限、默认开关与维护者此外命令行层的注册在 pkg/addons/config.go它决定了该 Addon 是否出现在minikube addons list中以及启用/禁用时要触发哪些回调。后文会逐步展开这四层的具体写法。从源码结构看整个 addon 系统还支持两种特殊形态一类是带有自定义逻辑的 Addon如gcp-auth、auto-pause、gvisor它们注册了额外的callbacks/validations另一类是基于 Helm Chart 的 Addon如traefik见 pkg/minikube/assets/addons.go。本文先聚焦最通用的纯清单型 Addon。二、第一步创建 Addon 目录与清单文件2.1 Fork 并检出仓库首先 fork minikube 仓库并检出你的 forkgit clone gitgithub.com:username/minikube.git cd minikube2.2 创建子目录并放入 YAML在deploy/addons/下为你的 Addon 创建子目录mkdir deploy/addons/addon name把你的清单文件拷贝进去cp *.yaml deploy/addons/addon name以当前仓库中的registryAddon 为例它的清单目录是 deploy/addons/registry包含三个文件registry-rc.yaml.tmplReplicationController/Deployment、registry-svc.yamlService和registry-proxy.yaml.tmpl代理组件。一个值得注意的细节minikube 的 Addon 清单是 Go 模板.tmpl后缀运行时会被注入模板数据。例如 deploy/addons/registry/registry-rc.yaml.tmpl 中的镜像字段image: {{.CustomRegistries.Registry | default .ImageRepository | default .Registries.Registry }}{{.Images.Registry}}这行模板依次回退到用户自定义 registry → 集群级--image-repository→ Addon 默认 registry再拼接上镜像名。模板数据由 pkg/minikube/assets/addons.go 的GenerateTemplateData生成其中包含KubernetesVersion、Arch、ImageRepository、LoadBalancerStartIP、LoadBalancerEndIP、ContainerRuntime、Images、Registries、CustomRegistries、NetworkInfo等字段。另一个典型例子是 deploy/addons/metallb/metallb-config.yaml.tmpl它把minikube start --load-balancer-start-ip/--load-balancer-end-ip的配置渲染进 MetalLB 的地址池addresses: - {{ .LoadBalancerStartIP }}-{{ .LoadBalancerEndIP }}2.3 需要 GCP 认证时的可选 Label如果这个 Addon永远不需要GCP 认证即不希望 gcp-auth 把 GCP 凭据挂载进它的 Pod建议在 Pod 的 YAML 上加上以下标签gcp-auth-skip-secret: true该标签的实际语义可以在源码中验证pkg/addons/addons_gcpauth.go 在刷新 Pod 挂载凭据时会跳过带gcp-auth-skip-secret标签的 Pod// Skip pods were explicitly told to skip if _, ok : p.Labels[gcp-auth-skip-secret]; ok { continue }同时启用 gcp-auth 时终端会输出提示如果不想让某个 Pod 挂载凭据就给它的配置加上gcp-auth-skip-secret标签见 pkg/addons/addons_gcpauth.go。三、注册 Addon让minikube addons list认识它3.1 在 pkg/addons/config.go 中添加条目为了让新 Addon 出现在minikube addons list中需要在 pkg/addons/config.go 的Addons切片里添加一个条目。官方文档给出的registry示例适用于任何不需要自定义代码的 Addon{ name: registry, set: SetBool, callbacks: []setFn{EnableOrDisableAddon}, },在 pkg/addons/config.go 的完整注册表中可以看到Addon结构体包含四个字段字段含义nameAddon 名称必须与目录名一致set把值写入配置的函数常规 Addon 统一用SetBoolvalidations启用前的前置校验可为空例如gvisor要求运行时是 containerdisRuntimeContainerd、nvidia-driver-installer要求 KVM 驱动isKVMDriverForNVIDIA、csi-hostpath-driver要求先启用 volumesnapshotsisVolumesnapshotsEnabledcallbacks启用/禁用时执行的回调链。最基础的是EnableOrDisableAddon需要校验 Pod 是否就绪的 Addon如ingress、registry、metrics-server、traefik、csi-hostpath-driver还会追加verifyAddonStatus以auto-pause为例它比普通 Addon 多了一个自定义回调{ name: auto-pause, set: SetBool, callbacks: []setFn{EnableOrDisableAddon, enableOrDisableAutoPause}, },而gcp-auth的回调链最长因为它还要负责把 GCP 凭据挂载进集群内所有 Pod{ name: gcp-auth, set: SetBool, callbacks: []setFn{enableOrDisableGCPAuth, EnableOrDisableAddon, verifyGCPAuthAddon}, },3.2 回调链的执行顺序从源码看回调的执行有严格的先后顺序pkg/addons/addons.goRunCallbacks先运行validations再运行callbacks任一步返回错误都会中断后续流程。EnableOrDisableAddon内部pkg/addons/addons.go的核心流程是解析 bool 值检查 Addon 是否已处于目标状态isAddonAlreadySet通过 libmachine API 加载节点主机若集群未运行则只写配置、跳过实际部署调用SelectAndPersistImages处理镜像选择与持久化支持--addon-images、--addon-registries覆盖生成模板数据GenerateTemplateData调用enableOrDisableAddonInternal启用时把资源拷贝进 VM 并kubectl apply禁用时删除资源文件并kubectl deleteapply 失败会按指数退避重试最多约 2 分钟。四、嵌入资源deploy/addons/assets.go 中的 //go:embed清单文件写好后需要通过//go:embed指令把它们嵌入二进制。编辑 deploy/addons/assets.go新增一个embed.FS变量。官方文档给出的是csi-hostpath-driver的示例// CsiHostpathDriverAssets assets for csi-hostpath-driver addon //go:embed csi-hostpath-driver/deploy/*.tmpl csi-hostpath-driver/rbac/*.tmpl CsiHostpathDriverAssets embed.FS当前仓库中该变量实际嵌入的范围更广deploy/addons/assets.go把 deploy 与 rbac 目录下的.tmpl和.yaml全部纳入//go:embed csi-hostpath-driver/deploy/*.tmpl csi-hostpath-driver/deploy/*.yaml csi-hostpath-driver/rbac/*.yaml CsiHostpathDriverAssets embed.FS//go:embed的匹配规则是从deploy/addons/目录即 assets.go 所在目录出发的 glob 模式可以同时写多个模式。整个 deploy/addons/assets.go 文件里定义了 40 余个嵌入变量几乎每个 Addon 一个命名惯例是AddonNameAssets。注意embed.FS是只读的虚拟文件系统运行时通过MustBinAsset(addons.XXXAssets, 相对路径, ...)来按路径取出文件内容。五、声明文件清单pkg/minikube/assets/addons.go这是最关键的登记步骤在 pkg/minikube/assets/addons.go 的Addonsmap 中为该 Addon 添加NewAddon条目声明要拷贝进集群的所有文件。官方文档的registry示例registry: NewAddon([]*BinAsset{ MustBinAsset(addons.RegistryAssets, registry/registry-rc.yaml.tmpl, vmpath.GuestAddonsDir, registry-rc.yaml, 0640, false), MustBinAsset(addons.RegistryAssets, registry/registry-svc.yaml.tmpl, vmpath.GuestAddonsDir, registry-svc.yaml, 0640, false), MustBinAsset(addons.RegistryAssets, registry/registry-proxy.yaml.tmpl, vmpath.GuestAddonsDir, registry-proxy.yaml, 0640, false), }, false, registry, google),5.1 MustBinAsset 参数详解MustBinAsset定义于 pkg/minikube/assets/vm_assets.go的签名是func MustBinAsset(fs embed.FS, name, targetDir, targetName, permissions string) *BinAsset各参数含义如下参数含义典型值fs资源所在的 embed.FS 变量addons.RegistryAssets定义于 deploy/addons/assets.goname源文件名相对 assets.go 的路径registry/registry-rc.yaml.tmpltargetDir虚拟机内的目标目录通常为vmpath.GuestAddonsDirtargetName拷贝后在虚拟机内的文件名registry-rc.yaml会去掉.tmpl后缀因为模板已在本地渲染permissions目标文件权限通常为06405.2 关于模板替换与默认启用的布尔值注意官方文档中示例代码的最后多了一个布尔参数控制是否做模板替换而当前仓库中MustBinAsset的签名是 5 个参数——模板替换不再由该参数控制而是由源文件名是否以.tmpl结尾自动判定见 pkg/minikube/assets/addons.goaddon.IsTemplate()为真时调用addon.Evaluate(data)渲染模板。因此现在写代码时应使用 5 参数形式。5.3 NewAddon 的其余参数NewAddon的完整签名pkg/minikube/assets/addons.gofunc NewAddon(assets []*BinAsset, enabled bool, addonName, maintainer, verifiedMaintainer, docs string, images, registries map[string]string, helmChart *HelmChart) *Addon第二个参数enabledAddon 是否默认启用。新 Addon 必须写false。当前仓库中仅default-storageclass和storage-provisioner为true。maintainer 字段告知用户该 Addon 镜像的控制方。例如registry的维护者是 minikube 团队当前仓库里写的是minikubefreshpod是Googlemetallb是3rd party (MetalLB)。创建新 Addon 时应当联系镜像来源方询问其是否愿意作为该 Addon 的联系人若对方不接受留空也是可以的例如kubeflow就写的是3rd party。verifiedMaintainer可选的维护者 GitHub 用户名如traefik的traefik、headlamp的yolossn。images / registriesAddon 使用的镜像名与默认 registry 的映射。例如 registry Addonmap[string]string{ KubeRegistryProxy: minikube/kube-registry-proxy:v0.0.11sha256:e321acf067df0a78fba3ff97748c10029ca2c413c5b7207e4ca000c62fcdac93, Registry: registry:3sha256:1be55279f18a2fe1a74edf2664cac61c1bea305b7b4642dab412e7affdcb3e33, }, map[string]string{ KubeRegistryProxy: registry.k8s.io, Registry: docker.io, },这些镜像引用会在模板渲染时作为{{.Images.XXX}}/{{.Registries.XXX}}使用并支持通过minikube addons enable name --addon-images keyvalue --addon-registries keyvalue覆盖见 pkg/minikube/assets/addons.go 的SelectAndPersistImages。helmChart如果该 Addon 基于 Helm Chart 安装则传HelmChart{...}此时Assets可为空。traefik是当前仓库唯一的 Helm 型 Addonpkg/minikube/assets/addons.go它指定了 Chart 仓库、命名空间与Values覆盖项并通过service.labels.kubernetes\.io/minikube-addons-endpointtraefik支持minikube addons open traefik。更多新增 Addon 的历史范例可以查看 deploy/addons 目录的提交历史基于 Helm 的 Addon 则参见仓库中的 Helm Based Addons若该页面存在于你的仓库版本中。六、支持minikube addons openNodePort Service 标签如果你的 Addon 包含 NodePort 类型的 Service请为它添加kubernetes.io/minikube-addons-endpoint: addon name标签minikube addons open命令依赖它来发现可打开的端点apiVersion: v1 kind: Service metadata: labels: kubernetes.io/minikube-addons-endpoint: addon name在源码中traefik正是通过给 Service 打上kubernetes.io/minikube-addons-endpointtraefik标签来让minikube addons open traefik可用的pkg/minikube/assets/addons.go。已知限制minikube addons open目前只对kube-system命名空间生效对应上游 issue #8089。因此如果 Service 部署在其他命名空间需要确认open行为是否符合预期。七、测试 Addon 改动修改清单或代码后重新构建 minikube 二进制并以开启详细日志的方式启用 Addonmake make test ./out/minikube addons enable addon name --alsologtostderr注意每次修改 YAML 文件后都必须重新执行make因为清单是通过//go:embed编译进二进制的不重新构建就不会生效。同样make test会运行 pkg/addons/addons_test.go、pkg/addons/validations_test.go 等单元测试覆盖SetBool、EnableOrDisableAddon及各类校验逻辑。当需要应用新的改动时先禁用再重新启用./out/minikube addons disable addon name --alsologtostderr--alsologtostderr会把 klog 日志同时输出到标准错误便于观察模板渲染、文件拷贝、kubectl apply/delete的详细过程。调试时还可以关注这些关键日志点均在 pkg/addons/addons.goSetting addon %s%s in %q开始处理某个 Addoninstalling %s/Removing %v逐个拷贝/删除目标文件apply failed, will retry: %vapply 失败后进入指数退避重试。八、提交流程发送 PR完成本地测试后点击 new pull request 向 minikube 主仓库发起 PR。合入前的最终自查清单deploy/addons/addon name/目录包含全部清单文件不需要 GCP 认证的 Pod 已加gcp-auth-skip-secret: true标签pkg/addons/config.go 中已注册该 Addonminikube addons list可见deploy/addons/assets.go 中已添加//go:embed变量pkg/minikube/assets/addons.go 中已添加NewAddon条目第二个参数为false不默认启用并填好 maintainer含 NodePort Service 时已加kubernetes.io/minikube-addons-endpoint标签make make test通过addons enable/disable验证成功。九、结语从上述流程可以看到minikube 的 Addon 体系是一条声明式的流水线清单文件 →//go:embed嵌入 →assets.Addons声明 →config.go注册四步即可让一个新 Addon 完整可用且天然支持list、enable、disable、open全部命令。若你的 Addon 需要更复杂的生命周期逻辑如运行时校验、自定义部署行为可以仿照gvisor、auto-pause、gcp-auth注册额外的validations与callbacks并在 pkg/addons 目录下实现对应的回调函数。这正是 minikube 生态能够不断扩展内置能力从 Ingress、Metrics Server 到 Istio、KubeVirt、gVisor的底层机制所在。【免费下载链接】minikubeRun Kubernetes locally项目地址: https://gitcode.com/gh_mirrors/mi/minikube创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考