资讯动态

云原生网关高可用演进:基于 Kong DaemonSet 与 Local 流量亲和力的跨节点零绕路改造

发布时间:2026/8/5 9:49:28 来源:尧图企业网站定制
云原生网关高可用演进基于 Kong DaemonSet 与 Local 流量亲和力的跨节点零绕路改造在跨云及混合云Cloud Homelab Edge部署 Kubernetes 集群的场景中API 网关作为整个系统的流量入口其部署架构与网络转发策略直接决定了服务的延迟、可用性与安全性。本文记录了一次对 Kong Ingress ControllerKIC的完整高可用与网络链路优化改造。针对原有架构中单点控制器、跨节点流量绕路以及缺乏 L4 TCP 转发能力等工程痛点通过GitOps 声明式配置完成了从 Deployment 到 DaemonSet 的平滑演进结合externalTrafficPolicy: Local实现了真正的节点级流量亲和Node-Affinity Routing与 L4 Stream 转发就绪。整个过程完全走 ArgoCD 自动同步没有手动 kubectl 改生产配置。中途踩了一个nginx_stream_listen假字段的坑导致 Kong 短暂 CrashLoopBackOff最后通过查 chart 源码确认了正确做法。这些细节都会写在后面。一、 现状盘点与痛点分析现有的集群由 3 个物理/云端异构节点跨网络组网而成腾讯云节点 (vm-0-2-debian)云端主节点承载控制面及部分接入服务。OCI ARM 节点 (free-arm-vm)公有云高算力节点4核24G ARM承载容器化数据面。本地 NUC 节点 (nuc)Homelab 边缘计算节点通过 Tailscale/专线隧道接入集群。在本次改造前网关层运行面临三个核心结构性缺陷1. 控制面/数据面 Pod 存在单点故障与跨节点漫游原有的 Kong Ingress Controller 采用标准的 K8sDeployment形态部署仅设置了单个 Pod 副本随机调度在腾讯云主节点上。当 OCI 节点或 NUC 节点的边缘入口收到外部请求时Pod 内部流量必须强行通过跨节点叠加网络Overlay Network网回腾讯云节点上的单点 Kong Pod 进行代理带来了显著的物理网络延迟开销。而且这个唯一的 Kong Pod 一旦挂了整个集群的入口流量全部瘫痪。2.externalTrafficPolicy: Cluster导致的额外 SNAT 与源 IP 丢失Kong Proxy Service 的默认流量策略为Cluster。在该模式下svclb 收到流量后可能把请求转发到其他节点上的后端 Pod通过集群内 iptables/overlay 规则做全局转发。若请求打入 OCI 节点的入口但后端端点在腾讯云节点网络栈会强制进行源地址转换SNAT。这不仅增加了多余的内部网络跳数Extra Network Hops还导致后端服务无法感知客户端的真正物理 IP。3. L7 代理局限与缺乏 L4 (TCP Stream) 传输能力默认的 Kong 部署仅启用了 HTTP/HTTPS (80/443) 端口代理。对于后续需要经由网关统一认证与审计的 Layer 4 流量如 Redis 6379、MySQL 3306现有网关未能开启 Nginx Stream 模块缺乏 L4 TCP 流量透传能力。二、 改造前后架构拓扑对比1. 改造前拓扑单点集中 跨节点强制绕路说明图中的入口组件是svclbK3s 为 LoadBalancer Service 自动生成的 DaemonSet每个节点一个监听 31850 端口用 iptables DNAT 转发到 Kong Controller。svclb 是 K3s 自带的基础设施一直就是 DaemonSet与本次改造无关——本次改造的对象是 Kong Controller 的部署形态Deployment 单副本 → DaemonSet 每节点一个。本地 NUC 节点 (nuc)OCI ARM 节点 (free-arm-vm)腾讯云节点 (vm-0-2-debian)外部客户端HTTP 请求HTTP 请求HTTP 请求本地 iptables DNAT跨云跨节点流量绕路跨网络隧道流量绕路转发跨节点转发Client AClient BClient Csvclb (K3s 自动生成 DaemonSet)监听 :31850Kong Controller (Deployment 单副本)改造前: 只有这一个Backend Service Asvclb (K3s 自动生成 DaemonSet)监听 :31850Backend Service Bsvclb (K3s 自动生成 DaemonSet)监听 :31850改造前隐患svclb 收到流量后如果后端 Kong Pod 不在本节点单副本在腾讯云流量必须跨网折返回腾讯云节点不仅增加了可观的网络延迟且当腾讯云上的单个 Kong Pod 发生 OOM 或被驱逐时整个集群的入口流量瞬间瘫痪。2. 改造后拓扑DaemonSet 全覆盖 本地流量亲和 L4/L7 双栈就绪本地 NUC 节点 (nuc)OCI ARM 节点 (free-arm-vm)腾讯云节点 (vm-0-2-debian)外部客户端HTTP / TCPHTTP / TCPHTTP / TCPexternalTrafficPolicy: Local本节点 iptables 就近拦截externalTrafficPolicy: Local本节点 iptables 就近拦截externalTrafficPolicy: Local本节点 iptables 就近拦截本地零跳路由跨节点代理 overlay本地零跳路由跨节点代理 overlay跨节点代理 overlay跨节点代理 overlayClient AClient BClient Csvclb (K3s 自动生成 DaemonSet)监听 :31850Kong Controller (DaemonSet)改造后: 每节点 1 个HTTP L4 Stream:6379Backend Service Asvclb (K3s 自动生成 DaemonSet)监听 :31850Kong Controller (DaemonSet)改造后: 每节点 1 个HTTP L4 Stream:6379Backend Service Bsvclb (K3s 自动生成 DaemonSet)监听 :31850Kong Controller (DaemonSet)改造后: 每节点 1 个HTTP L4 Stream:6379重要澄清代理能力 vs 入口链路externalTrafficPolicy: Local只作用于svclb → Kong这一段入口链路——保证流量打到哪个节点就由哪个节点的 Kong 就近接管实现入口零跨节点绕路。但Kong → backend 这一段是集群全量视角每个 KIC Pod 都通过 Kubernetes API watch 到集群内所有Service 与 Endpoint因此任意节点的 Kong 都能代理任意节点的 backend Service——本地有 backend 的走本节点 Pod 网络零跳直达实线本地没有的走 overlay 跨节点转发虚线功能不受限只是多一跳网络开销。NUC 节点虽然自身没有 backend 服务它的 Kong 同样能代理 Svc1/Svc2。改造后优势每个节点均运行独立的 Kong ControllerDaemonSetsvclb 收到流量后直接在本节点的 iptables 层拦截并送入本地 Kong Pod实现了真正的零跨节点网络损耗与真实源 IP 保留。同时保留全集群代理能力任意入口都能路由到任意 backend单节点故障不影响其他节点的入口。三、 解决方案与技术实现基于 GitOps 哲学所有改造禁止手动操作kubectl完全通过修改管理仓库my-argocd-manifests中的 Helm Values 声明式配置由 ArgoCD 捕获变更并自动同步。1. 目标 1将 Controller 调整为 DaemonSet 模式修改 Helm 的deployment配置使用官方支持的daemonset: true开关摆脱手动声明replicas的硬编码限制。使得集群无论何时加入或移除节点如动态扩容Kong 均能自动在每个节点上拉起 1 个 Pod 副本。为什么不用 replicas: 3因为那是硬编码。集群加一个节点replicas: 3不会自动变 4而 DaemonSet 天生就是每个节点一个 pod节点数变了它自动跟着变。Kong chart 的模板逻辑deployment.yaml里明确写着daemonset: true时渲染成 DaemonSet 并省略 replicas 字段。2. 目标 2配置externalTrafficPolicy: Local在 Kong Proxy Service 中强制开启Local流量策略。重要部署顺序契约externalTrafficPolicy: Local的要求是接收流量的节点上必须存在对应的端点 Pod否则该节点入口的流量将被直接丢弃。因此在工程实施上必须保证“目标 1 DaemonSet 先全量 Ready目标 2 才能切换 Local”严禁反向操作。3. 目标 3开启 Nginx Stream (TCP 6379) 转发能力正确的做法是在 Helm Values 的proxy选项中配置stream列表proxy:stream:-containerPort:6379servicePort:6379注意不需要、也不应该手动设置env.nginx_stream_listen这一点我们实际踩坑验证过——加了反而会导致 Kong 崩溃详见第五节踩坑记录。Kong chart 的helpers.tpl里proxy.stream会自动生成KONG_STREAM_LISTEN环境变量手动加字段是画蛇添足。四、 GitOps 配置文件变更明细修改仓库nvd11/my-argocd-manifests应用配置文件argocd-apps/kong-controller-app.yaml完整声明式配置更改内容如下apiVersion:argoproj.io/v1alpha1kind:Applicationmetadata:name:kong-ingress-controllernamespace:argocdannotations:argocd.argoproj.io/sync-wave:2spec:project:defaultsource:repoURL:https://charts.konghq.comchart:kongtargetRevision:2.38.0helm:values:|ingressController: installCRDs: false env: database: off # 注意: 不要手动加 nginx_stream_listen! # proxy.stream 会自动生成 KONG_STREAM_LISTEN gateway: enabled: true deployment: # 目标 1: 启用 DaemonSet 模式, 自动在每个 Node 部署 1 个 Pod 副本 daemonset: true proxy: # 目标 2: 强制节点本地流量亲和, 消除跨节点绕路, 保留客户端源 IP externalTrafficPolicy: Local # 目标 3: 开启 6379 端口的 TCP 流量透传能力 stream: - containerPort: 6379 servicePort: 6379destination:name:tencent-dp1-clusternamespace:kong-systemsyncPolicy:automated:prune:trueselfHeal:truesyncOptions:-CreateNamespacetrue-ServerSideApplytrue五、 部署与实操验证过程1. 提交代码并触发 GitOps 流水线三个目标的改动分三次提交推送每次都等 ArgoCD 自动同步# 目标 1: DaemonSet 模式gitcommit-mfeat(kong): deploy controller as DaemonSet (one pod per node)# 8dc3fb9gitpush origin main# 目标 2: Local 策略gitcommit-mfeat(kong): set externalTrafficPolicy to Local for node-affinity routing# 95a434agitpush origin main# 目标 3: TCP stream (第一次, 踩坑版)gitcommit-mfeat(kong): enable TCP stream proxy on 6379# f9470cdgitpush origin main# ... 发现崩溃, 修复后 ...gitcommit-mfix(kong): remove invalid nginx_stream_listen, proxy.stream auto-generates KONG_STREAM_LISTEN# 0847444gitpush origin mainArgoCD 捕获每次变更后自动调度更新tencent-dp1-cluster集群中的资源一般 1-3 分钟内完成。2. 检查 DaemonSet 及 Pod 节点分布同步完成后验证 DaemonSet 是否在 3 个节点上均成功处于Ready状态$ kubectl get ds-nkong-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE AGE kong-ingress-controller-kong3333325m $ kubectl get pods-nkong-system-owide NAME READY STATUS NODE IP kong-ingress-controller-kong-lstfr2/2 Running vm-0-2-debian10.42.0.246 kong-ingress-controller-kong-rxn4r2/2 Running free-arm-vm10.42.2.12 kong-ingress-controller-kong-w8qkb2/2 Running nuc10.42.1.16结果显示3 个节点分布完全均匀各自绑定本节点 Pod。小插曲nuc 节点的 pod 一度卡在Init:0/1超过 15 分钟——不是故障是 nuc 走 DaoCloud 镜像源拉kong:3.6太慢约 100KB/s17 分钟才拉完。期间腾讯云和 OCI 两个节点已经就绪HTTP 路由不受影响。想干预加速从别的节点导镜像传过去结果 kubelet 后台自己拉完了干预反而多余。结论DaemonSet 滚动更新时慢节点的 pod 会自己追上不用慌。3. 验证 Proxy Service 的策略变更核实 Service 对象的externalTrafficPolicy属性已正确刷新$ kubectl get svc-nkong-system kong-ingress-controller-kong-proxy-ojsonpath{.spec.externalTrafficPolicy}Local4. 验证三节点入口 HTTP 路由连通性对三个节点的 NodePort 入口分别发起 HTTP 请求测试验证路由准确性# 1. 腾讯云入口$curl-s-o/dev/null-wTencent Node: %{http_code}\nhttp://100.77.64.95:31850/svc2 Tencent Node:307# 307 是 Kong 重定向, 跟随后返回 200# 2. OCI ARM 入口$curl-s-o/dev/null-wOCI Node: %{http_code}\nhttp://100.105.130.0:31850/svc2 OCI Node:307# 3. 本地 NUC 入口$curl-s-o/dev/null-wNUC Node: %{http_code}\nhttp://100.104.150.19:31850/svc2 NUC Node:307三个节点入口响应全部正常307 重定向跟随后 200。而且 NUC 入口的响应时间明显更短0.02s vs 腾讯云 0.9s——Local 策略下 NUC 的 svclb 直接找本节点 controller零跨节点转发这就是效果的直观体现。顺带一个反证/svc2是部署在 OCI 节点上的 Backend Service B但腾讯云入口100.77.64.95:31850和 NUC 入口100.104.150.19:31850也能访问它——这说明任意节点的 Kong 都在代理 OCI 的 backend正是图里每个 KIC 全量代理所有节点 backend Service的直接证据。externalTrafficPolicy: Local约束的只是流量进哪个节点的 KongKong 拿到请求后路由到哪个 backend 完全是集群全量视角跟入口节点无关。4.1 关键验证Local 策略的流量本地化铁证仅仅三个入口都通还不足以证明 Local 生效。我做了更严格的对照实验——从本机100.115.214.26发起逐个入口单独打请求然后看每个 controller 的访问日志# 实验 1: 只打 OCI 入口 3 次$curlhttp://100.105.130.0:31850/svc2# ×3# 看各 controller 日志 (来源 IP 时间戳)$ kubectl logs-nkong-system kong-ingress-controller-kong-rxn4r-cproxy|grepGET /svc2100.115.214.26 - -[02/Aug/2026:17:54:31]GET /svc2307← OCI controller 收到3次# 腾讯云 controller (lstfr): 无请求# NUC controller (w8qkb): 无请求# 实验 2: 只打 NUC 入口 3 次$curlhttp://100.104.150.19:31850/svc2# ×3# NUC controller (w8qkb) 收到 3 次, 其他无结论打 OCI 入口 → 只有 OCI 节点的 controller 处理打 NUC 入口 → 只有 NUC 的 controller 处理。零跨节点转发。而且日志里来源 IP 是真实的客户端 IP100.115.214.26没有被 SNAT 成节点 IP——Local 策略保留源 IP 的效果也验证了。顺带说一句第一版验证踩了个小坑——用kubectl logs -c proxy看到的是 Kong 每 3 秒一次的/status健康检查日志不是真实流量。要 grep 掉/status才能看到真实请求。5. 验证 TCP Stream 监听就绪从集群外直接测试三个节点的 6379 端口 TCP 连通性最直接的验证不需要进容器$foripin100.77.64.95100.105.130.0100.104.150.19;dotimeout5bash-cecho /dev/tcp/$ip/6379echo$ip:6379 → 开放||echo$ip:6379 → 不通done100.77.64.95:6379 → 开放100.105.130.0:6379 → 开放100.104.150.19:6379 → 开放三个节点全部监听 6379。Kong 的 stream 模式已开启TCP 转发能力就绪后续挂TCPIngress路由即可用。6. 踩坑记录nginx_stream_listen是个假字段这是本次改造最大的坑值得单独写一段。第一版目标 3 配置我加了两样东西proxy.streamenv.nginx_stream_listen: [::]:6379。结果 ArgoCD 同步后腾讯云节点的新 pod 立刻 CrashLoopBackOffError: could not prepare Kong prefix at /kong_prefix: nginx configuration is invalid (exit code 1): nginx: [emerg] listen directive is not allowed here in /kong_prefix/nginx-kong-stream.conf:29排查过程看 pod 事件 → CrashLoopBackOffnginx 配置校验失败看日志 →listen directive is not allowed here出现在 stream 配置里查 Kong chart 源码helpers.tpl→ 发现proxy.stream会自动生成KONG_STREAM_LISTEN环境变量kong.streamListenhelper第 1046-1057 行结论nginx_stream_listen不是 chart 支持的字段被当成裸 nginx 指令注入格式错误导致崩溃修复移除nginx_stream_listen只保留proxy.stream→ 重新同步 → 3 个 pod 全部 Running6379 全部监听。经验配 Kong chart 时能用 chart 原生字段proxy.stream就绝不要手动加环境变量。先查 chart 源码确认字段是否存在别凭直觉加。六、 总结与工程最佳实践本次改造以极小的配置侵入量完成了网关层的高可用升级与架构重构解耦集群节点扩展与网关配置采用 DaemonSet 替代特定副本数的 Deployment将节点扩缩容与网关 Pod 伸缩完全解耦提升了混合云拓扑下的自愈能力。硬编码replicas: 3是坏味道——集群加节点不会自动变 4DaemonSet 才会。践行真正的“零绕路”低延迟网络通过externalTrafficPolicy: Local将跨节点的二层/三层网络转发削减至 0降低了网关代理延迟同时保障了客户端 IP 的原样透传。验证时 NUC 入口 0.02s vs 腾讯云 0.9s 的对比就是直观证据。保持声明式架构的完整度全过程均通过 ArgoCD GitOps 管道完成更新确保了环境可重复构建与配置的“单一事实来源Single Source of Truth”。部署顺序是硬约束先 DaemonSet 全量 Ready再切 Local。顺序反了没有本节点后端的入口会直接丢流量。验证要严谨HTTP 全通只是必要条件不是充分条件。用逐个入口单独打 看各 controller 日志的对照实验才能铁证 Local 生效。健康检查日志/status会污染统计要过滤。chart 字段先查源码nginx_stream_listen的坑告诉我们配 Helm chart 前先 grep 一下 chart 源码确认字段真实存在能省一次 CrashLoopBackOff。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价