设计解析:打造可复用的网关 Helm 渲染与部署框架)
API网关云原生微服务【免费下载链接】kgatewayThe Cloud-Native API Gateway and AI Gateway项目地址https://gitcode.com/gh_mirrors/kg/kgateway点击查看免费下载作为云原生 API 网关与 AI 网关kgateway 的核心能力之一是根据用户声明的Gateway、GatewayClass与GatewayParameters资源自动渲染并下发一组代理工作负载Envoy Deployment、Service、ServiceAccount、ConfigMap 等到 Kubernetes 集群。负责这一能力的组件被称为Deployer。本文围绕设计文档 design/11376-modular-deployer.mdEP-11376展开剖析 kgateway 如何将 Deployer 从与网关 Helm 渲染实现深度耦合的内部包重构为可公开复用、可扩展的公共子模块。读完本文你将理解 Deployer 的现状耦合点、HelmValuesGenerator/HelmConfig等核心抽象的引入动机与使用方式、GatewayParameters 合并逻辑的可复用设计以及渲染到集群落地的完整调用链。一、背景Deployer 承担了什么职责在 kgateway 中Deployer 负责自动化部署两类工作负载Gateway网关为每个Gateway渲染并部署 Envoy 代理实例Inference Pool推理池为 AI/LLM 推理工作负载如 vLLM渲染并部署 endpoint picker 等辅助组件。设计文档明确指出改造前的 Deployer 实现与其内部表示形式深度耦合它强依赖网关Gateway、网关参数GatewayParameters、关联 Helm chart values 的内部表示而 inference pool 扩展则被当作一种特例处理——但其实现仍然大量借用了最初为网关开发的那套抽象。这种耦合带来的直接后果是渲染网关/推理池 chart 的逻辑被硬编码在 Deployer 内部无法被其他组件或外部项目复用生成的 helm values 存放在包内不可见的helmConfig中无法在包外访问或二次处理只要想部署一种新的组件类型就必须修改 Deployer 本身而不是以插件式方式扩展。从当前仓库的源码布局可以印证这一改造的结果设计落地后公共可复用部分位于 pkg/deployer 目录而网关专属的实现则收敛到 pkg/kgateway/deployer 目录二者通过接口解耦。二、设计目标与非目标EP-11376 明确列出了本次改造的四个目标将 Deployer 与网关/推理池 Helm chart 渲染的实现细节解耦——渲染逻辑不再硬编码在 Deployer 内将 Deployer 变成公共子模块以便复用——从internal/deployer提升为公开的pkg/deployer支持任意的 GatewayParameters 扩展——第三方可以通过自定义HelmValuesGenerator注入自己的渲染逻辑让 GatewayParameters 合并逻辑可供复用——将深度合并deep merge算法从内部实现提炼为公开函数。同时设计也划定了明确的非目标Non-Goals不复用 kgateway controller 与 inference extensions controller本次只改造 Deployer 本身不试图统一两套控制器不支持单个 Deployer 实例管理多个 chart一个 Deployer 实例仍然只对应一个 Helm chart不做 Helm chart 渲染的优化渲染性能优化不在本次范围内。这些边界保证了改动范围可控也说明模块化关注的是职责拆分与接口开放而非功能扩展。三、改造前Deployer 的现状与耦合点设计文档用一张架构图design/resources/deployer-current-implementation.png刻画了改造前的实现结构改造前 kgateway Deployer 的实现结构与耦合点图中六个要素说明了当时的职责划分Deployer对外暴露一组渲染函数GetObjsToDeploy、GetEndpointPickerObjs和部署函数DeployObjs。它通过硬编码逻辑和配置第 4 点的 Inputs来自动决定自己是部署网关还是推理池两类组件的 values 渲染与 chart 渲染都是internal/deployer包内的实现细节包外不可见helmConfig存放GetObjsToDeploy与GetEndpointPickerObjs调用过程中生成的 helm values仅限包内访问Chart对 Helm charthelm 模块的引用Inputs一组用于配置 Deployer 的选项包括控制面 xDS 配置、inference extension 配置、镜像仓库配置等渲染 chart 时使用 5、6.Controllers通过 Deployer 渲染 kgateway chart 与 inference extension chart然后把变更同步到 Kubernetes 集群。可以看到渲染什么 chart、生成什么 values和如何部署对象全部挤在同一个包里任何新组件类型的引入都会迫使修改 Deployer 本体。四、改造后模块化的公共 Deployer 子模块改造后的架构见设计文档的另一张图design/resources/deployer-proposed-changes.png改造后模块化 Deployer 的架构设计Deployer 移入pkg/deployer包接口收敛为两个核心方法GetObjsToDeploy渲染 chart与DeployObjs同步对象到集群Inputs 移入pkg/deployer包它是 Deployer 的直接依赖创建 Deployer 实例必须提供Chart 的加载职责转移chart 不再在 Deployer 工厂函数内加载而是由controllerBuilder负责HelmValuesGenerator 成为通用接口负责为 chart 生成 helm values。网关参数第 7 点与 inference extension第 8 点的实现在internal/deployer包中落地到当前仓库后位于 pkg/kgateway/deployerHelmConfig 变为公共结构体用于存放网关与推理扩展 chart 的 helm values以支持网关参数 helm values 生成的复用pkg/deployer/GatewayParameters模块让 kgateway 的默认配置参数可供复用 7、8.Helm values renderer由controllerBuilder实例化并注入 Deployer 实例 9、10.Controllers继续通过 Deployer 渲染两类 chart 并同步到集群。对比改造前后的图可以清楚看到渲染相关的一切细节values 怎么算、chart 是什么都从 Deployer 内部抽出来变成由外部注入的依赖。Deployer 本身只保留用给定 values 渲染 chart → 得到对象 → 下发到集群这条通用流水线。五、核心抽象一HelmValuesGenerator——渲染职责的注入点HelmValuesGenerator是本次改造最关键的新抽象定义在 pkg/deployer/helm_values_generator.gotype HelmValuesGenerator interface { // GetValues 返回用于渲染动态供给资源如 Gateway的 helm values。 // 如果返回 nil说明该对象是自管理的self-managed不应供给任何资源。 GetValues(ctx context.Context, obj client.Object) (map[string]any, error) // GetCacheSyncHandlers 返回 HelmValuesGenerator 控制器的缓存同步处理器 GetCacheSyncHandlers() []cache.InformerSynced }两个方法的语义非常明确GetValues对某个client.Object目前可以是Gateway执行查找、合并等操作得出最终 helm values。返回 nil 是一个关键约定——它表示对象是自管理的Deployer 不应为其供给任何资源。这一约定直接支持了GatewayParameters.Spec.SelfManaged语义当用户声明selfManaged: {}时kgateway 不会自动部署代理见 pkg/kgateway/deployer/gateway_parameters.go 中kgatewayParameters.GetValues的实现GetCacheSyncHandlersDeployer 侧控制器启动时需要等待这些 informer 同步完成保证渲染时拿到的 GatewayParameters、GatewayClass 是新鲜的。同一文件还定义了可选的扩展接口ObjectPostProcessortype ObjectPostProcessor interface { // PostProcessObjects 在 helm 渲染之后、部署之前对渲染出的对象做后处理。 // 返回值可能包含新增对象如 PodDisruptionBudget、HorizontalPodAutoscaler。 PostProcessObjects(ctx context.Context, obj client.Object, rendered []client.Object) ([]client.Object, error) }这正是设计目标 3支持任意的 GatewayParameters 扩展的实现落点网关专属的GatewayParameters生成器实现了该接口在渲染完成后把GatewayParametersOverlays以**战略合并补丁strategic merge patch**的形式叠加到 Deployment、Service、ServiceAccount 等对象上实现见 pkg/deployer/strategicpatch/strategicpatch.go可叠加 PDB/HPA/VPA 并追加新对象。为了让第三方能彻底替换渲染逻辑网关侧的GatewayParameters生成器还提供了WithHelmValuesGeneratorOverride(generator)方法一旦设置了 overrideDeployer 就会完全委托给它包括缓存同步与后处理见 pkg/kgateway/deployer/gateway_parameters.go。这意味着社区或企业用户完全可以写一个自己的HelmValuesGenerator注入到 Deployer 中从而实现任意 GatewayParameters 扩展。六、核心抽象二HelmConfig 与 Inputs 的公共化6.1 HelmConfig渲染 values 的公共数据结构改造后HelmConfig成为pkg/deployer的公共结构体pkg/deployer/values.gotype HelmConfig struct { Gateway *HelmGateway json:gateway,omitempty }HelmGateway则是 Gateway 渲染所需全部 values 的容器字段覆盖了 Helm chart 模板需要的所有维度按用途可分为几组命名与归属name、gatewayName、gatewayNamespace、gatewayClassName、gatewayAnnotations、gatewayLabels、nameOverride、fullnameOverride部署与服务replicaCount、ports、service、strategyServiceAccountserviceAccountPod 模板extraPodAnnotations、extraPodLabels、imagePullSecrets、podSecurityContext、nodeSelector、affinity、tolerations、startupProbe、readinessProbe、livenessProbe、extraVolumes、gracefulShutdown、terminationGracePeriodSeconds、topologySpreadConstraints、priorityClassName容器配置sdsContainerSDS 边车、istioContaineristio-proxy 边车、istioIstio 集成开关Envoy 容器logFormat、logLevel、componentLogLevel、image、resources、securityContext、extraArgs、env、extraVolumeMountsbootstrapdnsResolver、enableReadinessProbeProxyProtocolxDS 与统计xdshost/port/TLS、stats含基于 Envoy StringMatcher 的inclusionList/exclusionList统计匹配器。这些字段与 Helm chart 模板一一对应。以 pkg/kgateway/helm/envoy/templates/deployment.yaml 为例模板中直接消费$gateway.replicaCount、$gateway.strategy、$gateway.extraPodAnnotations、$gateway.ports、$gateway.gracefulShutdown、$gateway.istio.enabled等值。HelmConfig公共化之后任何需要生成这些 values 的代码都可以直接构造并复用这也是网关参数 helm values 生成可复用目标的数据基础。6.2 Inputs创建 Deployer 的环境信息Inputs在 pkg/deployer/gateway_parameters.go 中定义type Inputs struct { Dev bool IstioAutoMtlsEnabled bool ControlPlane ControlPlaneInfo ImageInfo *ImageInfo CommonCollections *collections.CommonCollections GatewayClassName string WaypointGatewayClassName string }其中ControlPlaneInfo携带XdsHost、XdsPort、XdsTLS、XdsTlsCaPath——代理启动时连接控制面 xDS 的地址与 TLS 信息ImageInfo携带Registry、Tag、PullPolicy用于渲染镜像。从源码结构可以推断Inputs是 Deployer 与其依赖环境之间的上下文对象将 xDS 配置、镜像配置、Istio 自动 mTLS 开关等集中传递避免每个渲染器各自去查。值得注意的是pkg/deployer/gateway_parameters.go还沉淀了默认网关参数的完整定义defaultGatewayParameters这相当于把kgateway 默认值作为公共资产暴露出来。从源码可以看到一组有代表性的默认值Service 类型为LoadBalancerTerminationGracePeriodSeconds: 60且默认开启优雅停机GracefulShutdownsleep 10sreadiness/startup 探针指向/ready端口 8082Envoy 容器LogLevel: infoDNS resolverUdpMaxQueries: 100安全的容器 SecurityContextRunAsNonRoot: true、RunAsUser: 10101、AllowPrivilegeEscalation: false、ReadOnlyRootFilesystem: true并Drop: [ALL]Stats 默认启用RoutePrefixRewrite: /stats/prometheus?usedonlyIstio 集成istio-proxy镜像固定为docker.io/istio/proxyv2默认 tag 为DefaultIstioProxyImageTag 1.31.0。此外GetInMemoryGatewayParameters提供了内置参数的优先级判定当ClassName等于WaypointClassName时返回 waypoint 专属参数ClusterIP Service、追加 mesh port、io.istio.dataplane-mode: ambient标签、关闭 zTunnel DNS 解析等否则返回默认网关参数。这个优先级行为有对应的单元测试覆盖pkg/deployer/gateway_parameters_test.go测试用例明确验证了waypoint class 优先、默认参数兜底的四种组合。七、GatewayParameters 合并逻辑merge.go 的复用能力设计目标 4 要求GatewayParameters 合并逻辑可供复用。这一目标落地为 pkg/deployer/merge.go 中的公开合并函数族核心入口是func DeepMergeGatewayParameters(dst, src *kgateway.GatewayParameters)合并规则在设计上非常讲究体现了默认值 用户覆盖的语义SelfManaged 短路若src.Spec.SelfManaged ! nil直接将 dst 置为 self-managed 并清空Kube字段跳过所有 kube 字段的合并因为自管理网关下这些字段无意义nil 即保留src为 nil 或src.Spec.Kube nil时直接使用 dst不做任何修改逐维度深合并Deployment、EnvoyContainer、SdsContainer、PodTemplate、Service、ServiceAccount、Istio、Stats、OmitDefaultSecurityContext各自有专门的深合并函数指针/标量用覆盖MergePointers与MergeComparable遵循src 非 nil/非零则取 src否则保留 dstMap 用并集DeepMergeMaps将 src 的所有条目并入 dstExtraLabels、ExtraAnnotations、NodeSelector 等Slice 用追加DeepMergeSlices对 nil src 保留 dst、对空 src 清空、否则追加——但需要按键唯一的列表如 sysctls使用按键合并deepMergeSysctls按名称索引src 同名值覆盖 dst避免 Kubernetes 拒绝重复的 sysctl 名存在语义冲突的字段用专用策略例如 probe 的 Handler 只保留 src 的一个 ActionExec/HTTPGet/TCPSocket/GRPC 互斥image的tag与digest联动指定其一而未指定另一时清空继承值形成repo:tag或repodigest的干净语义。这一整套合并语义由 pkg/deployer/merge_test.go约 942 行测试系统验证覆盖了src 覆盖 dst 副本数src nil 不覆盖selfManaged 清空 kube等大量组合场景。在网关渲染管线中这套逻辑被kgatewayParameters这样使用pkg/kgateway/deployer/gateway_parameters.go优先查找Gateway.Spec.Infrastructure.ParametersRef指向的GatewayParameters须与 Gateway 同 namespace且 group/kind 必须合法否则回退到GatewayClass.Spec.ParametersRef若都未配置则调用GetInMemoryGatewayParameters生成内存默认参数最终执行deployer.DeepMergeGatewayParameters(defaultGwp, gwp)把用户覆盖叠加到默认值之上保证镜像 registry/tag 等默认值在未显式覆盖时始终存在。也就是说默认值兜底 用户参数覆盖这套核心语义现在由pkg/deployer公共提供任何模块无论是 kgateway 自身的其他控制器还是第三方复用者都可以直接调用无需复制粘贴内部实现。八、从渲染到落地的完整链路模块化之后Deployer 的核心职责收敛为一条清晰的流水线实现在 pkg/deployer/deployer.go。结合 pkg/kgateway/controller/gw_controller.go 中gatewayReconciler.Reconcile的调用顺序完整链路如下第一步GetObjsToDeploy——渲染 chart 为对象func (d *Deployer) GetObjsToDeploy(ctx context.Context, obj client.Object) ([]client.Object, error) { vals, err : d.helmValues.GetValues(ctx, obj) // ① 由注入的 HelmValuesGenerator 计算 values ... objs, err : d.RenderToObjects(rns, rname, vals) // ② 用 values 渲染 chart ... if postProcessor, ok : d.helmValues.(ObjectPostProcessor); ok { objs, err postProcessor.PostProcessObjects(ctx, obj, objs) // ③ 可选后处理overlays } return objs, nil }①处vals nil表示自管理对象直接返回 nil 不供给资源②处实际调用RenderManifest其内部使用 Helm 库以ClientOnly模式执行install.Runpkg/deployer/deployer.go 的RenderManifest只做模板渲染、不触碰集群从根本上避免渲染过程阻塞控制器并保证函数能快速终止。第二步SetNamespaceAndOwnerWithGVK——设置命名空间与属主对每个渲染出的对象若是 namespace 作用域资源则补齐 namespace 并设置 controller ownerRef指向 Gateway 的 GVK若是集群作用域资源则清空 namespace。设计文档中的使用 ownerGVK 而非硬编码值的细节在这里体现为ownerRef 的 APIVersion/Kind 来自调用方传入的 GVK避免依赖 client-go 在 List 后丢失 TypeMeta 的问题。第三步DeployObjsWithSource——幂等下发该方法先按资源类型优先级排序SortByKindPriorityNamespace → ServiceAccount → Secret/ConfigMap → Role/ClusterRole → RoleBinding/ClusterRoleBinding → Service → 其他确保 RBAC、ServiceAccount、ConfigMap 等基础设施先于 Deployment 等工作负载应用避免 Pod 在 RBAC 就绪前启动的竞态。随后对每个对象执行 SSAServer-Side Apply补丁逻辑applyPatchTypeforcetruefieldManager 为 controllerName中间还做了关键的幂等优化从缓存读取现有对象并深拷贝先清空 API Server 会改写的字段resourceVersion、generation、UID、creationTimestamp、managedFields、status用equality.Semantic.DeepEqual比较新旧对象完全一致则跳过补丁减少无效写请求特别地对Service对象做属主校验validateExistingServiceOwnership如果现存的 Service 既没有指向来源对象的 controller ownerRef也没有匹配的managed-by标签与 gateway-class/gateway-name 标签则拒绝覆盖防止误动其他系统创建的 Service。第四步PruneRemovedResources——清理过期的 PDB/HPA/VPA配置变更导致 PodDisruptionBudget、HorizontalPodAutoscaler、VerticalPodAutoscaler 不再出现在期望集合中时该方法通过gateway.networking.k8s.io/gateway-name标签并使用SafeGatewayLabelValue截断处理超过 63 字符的 Gateway 名列出并删除已不再期望的资源避免陈旧资源残留。相关行为有独立测试 pkg/deployer/prune_test.go 覆盖。最后gatewayReconciler还会根据渲染出的 Service 回填 Gateway 的status.addresses并依据渲染结果设置Accepted条件渲染失败时置InvalidParameters恢复后回置Accepted。九、控制器侧如何注入与编排控制器侧的装配逻辑在 pkg/kgateway/controller/controller.go 的watchGw中体现得最为直观inputs : deployer.Inputs{ Dev: cfg.Dev, IstioAutoMtlsEnabled: cfg.IstioAutoMtlsEnabled, ControlPlane: cfg.ControlPlane, ImageInfo: cfg.ImageInfo, CommonCollections: cfg.CommonCollections, GatewayClassName: cfg.GatewayClassName, WaypointGatewayClassName: cfg.WaypointGatewayClassName, } gwParams : internaldeployer.NewGatewayParameters(cfg.Client, inputs) if helmValuesGeneratorOverride ! nil { gwParams.WithHelmValuesGeneratorOverride(helmValuesGeneratorOverride(inputs)) } d, err : internaldeployer.NewGatewayDeployer( cfg.ControllerName, cfg.Mgr.GetScheme(), cfg.Client, gwParams, deployer.WithManagedBy(wellknown.DefaultManagedByValue), )关键点在于NewGatewayDeployerpkg/kgateway/deployer/deployer_factory.gofunc NewGatewayDeployer(controllerName string, scheme *runtime.Scheme, client apiclient.Client, gwParams *GatewayParameters, opts ...deployer.Option) (*deployer.Deployer, error) { envoyChart, err : LoadEnvoyChart() // chart 加载职责在工厂函数中完成 ... return deployer.NewDeployer( controllerName, scheme, client, envoyChart, gwParams, GatewayReleaseNameAndNamespace, opts...), nil }这正是设计文档第 3 点chart 不再在 Deployer 工厂函数内加载而是成为 controllerBuilder 的职责的落地形态LoadEnvoyChart从内嵌的 pkg/kgateway/helm/envoy chart 加载为*chart.Chart然后作为参数传给通用的deployer.NewDeployer。而GatewayReleaseNameAndNamespace由于 Helm release 只用于模板生成、从不真正安装返回硬编码的占位名称release-name-placeholder。在gatewayReconcilerpkg/kgateway/controller/gw_controller.go中除了上述渲染→下发→剪枝→状态回填流程还注册了一系列事件处理器Gateway 的增删改、GatewayClass 变更联动触发同 class 下所有 Gateway 重排、GatewayParameters 变更分别经parametersRef索引与 class 索引找到受影响 Gateway、以及渲染产物Deployment/Service/ServiceAccount/ConfigMap的 owner 反查重排。这些编排逻辑与 Deployer 的渲染细节完全解耦——controller 只面向deployer.Deployer的公开接口编程。十、测试与验证模块化的公共接口与合并逻辑都有充分的测试支撑pkg/deployer/deployer_test.go约 2939 行覆盖从 Gateway 渲染出 Deployment/ServiceAccount 等对象、helm values 注入、对象属主与命名空间设置、幂等跳过、overlay 应用等核心行为pkg/deployer/merge_test.go约 942 行系统验证DeepMergeGatewayParameters及各字段的合并/覆盖/保留语义pkg/deployer/gateway_parameters_test.go验证 waypoint 与默认参数的优先级与端口差异pkg/deployer/prune_test.go验证 PDB/HPA/VPA 的剪枝行为集成层面还有 test/deployer/deployer_helm.go 与 test/deployer/internal_helm_test.go将渲染产物与真实 Helm 模板输出做对比断言。设计文档同时提到PoC 实现在PR #11377中完成文档内给出了对应的 diff 链接。从当前仓库的代码布局看该设计已完全落地公共抽象的接口签名、HelmConfig/Inputs的公共化、WithHelmValuesGeneratorOverride的扩展点均与文档中的规划一一对应。十一、设计取舍与后续演进设计文档的 Alternatives 一节提出了进一步的拆分方向Deployer 还可以继续拆分为 Applier应用者与 Rendered渲染结果两组接口及各自的默认实现。从当前源码看这一方向尚未实施属于可选的后继演进。从更宏观的角度看EP-11376 的模块化带来三个直接收益复用性任何需要用 Helm chart 渲染资源并下发到 Kubernetes的组件包括未来的第三方扩展、新的数据面类型都可以直接使用pkg/deployer只需实现HelmValuesGenerator可测试性渲染与部署被接口切分后可以用内存 chart、fake client 对流水线做细粒度测试而不必起真实集群演进空间ObjectPostProcessor与WithHelmValuesGeneratorOverride提供了两个不同层级的扩展点——前者做渲染后的对象改写overlay后者则允许完全替换 values 生成逻辑为任意 GatewayParameters 扩展留下了清晰的挂钩。结语EP-11376 的本质是一次职责边界的重新划分把生成 values 加载 chart 渲染 下发 清理这条通用流水线留在公共的pkg/deployer把网关/推理池专属的 values 怎么算推向由controllerBuilder注入的HelmValuesGenerator实现。正是这种解耦让 kgateway 的 Deployer 从一个内部特化工具进化为可复用的公共子模块——对于希望基于 kgateway 构建自定义代理部署逻辑的开发者理解HelmValuesGenerator、HelmConfig、Inputs与merge.go的合并语义是接入这套框架的起点。赞分享API网关云原生微服务【免费下载链接】kgatewayThe Cloud-Native API Gateway and AI Gateway项目地址https://gitcode.com/gh_mirrors/kg/kgateway点击查看免费下载相关推荐DiligentEngine架构深度剖析模块化设计与高性能渲染框架DiligentEngine架构深度剖析模块化设计与高性能渲染框架 DiligentEngine是一个现代化的跨平台低层3D图形库和渲染框架专为高性能图形应Meshery 部署设计解读Bitnami ClickHouse Helm Chart v9.4.4 在 Catalog 中的可复用部署设计Meshery 部署设计解读Bitnami ClickHouse Helm Chart v9.4.4 在 Catalog 中的可复用部署设计 本文以 Mesh云原生微服务运维DevOpsiOSProject组件化与模块解耦设计打造可维护的iOS应用架构iOSProject组件化与模块解耦设计打造可维护的iOS应用架构 在iOS应用开发中随着业务复杂度不断增加如何设计一个清晰、可维护的架构成为每个开发者必移动开发示例工程上一篇FastLED 寄存器映射开发规范以厂商 CMSIS PAL 头文件为唯一事实源Register Maps Vendor CMSIS Headers下一篇深度解析Umi-OCR Linux系统集成与自动化部署方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考