Istio ztunnel 滚动升级时如何利用 SO_REUSEPORT 与 drain 机制减少流量中断

发布时间:2026/9/10 18:50:33
Istio ztunnel 滚动升级时如何利用 SO_REUSEPORT 与 drain 机制减少流量中断 Istio ztunnel 滚动升级时如何利用 SO_REUSEPORT 与 drain 机制减少流量中断【免费下载链接】istioConnect, secure, control, and observe services.项目地址: https://gitcode.com/GitHub_Trending/is/istio在 ambient 模式下ztunnel 以 DaemonSet 方式运行每个节点一个接管该节点上所有 mesh Pod 的 L4 流量。当需要升级 ztunnel更换镜像版本或修改 DaemonSet spec时每个节点都会发生一次旧 Pod 退场、新 Pod 接管的滚动重启而流量中断风险就集中在这一瞬间。Istio 用SO_REUSEPORT加 drain连接排空两个机制保证整个过程中新连接随时都能成功。这篇文章基于仓库中的 ztunnel 生命周期文档 和 ztunnel Helm chart 说明这套机制如何工作、升级前应检查哪些配置项、以及如何判断升级是否达到预期效果。为什么 ztunnel 升级时流量无法无损接管在讨论配置之前先明确 ztunnel 升级时的能力边界。生命周期文档指出 ztunnel 只工作在 Layer 4这带来两个限制TCP 是有状态的旧 ztunnel 的连接状态无法直接传给新进程如果在 L3 层工作新进程直接处理报文即可ztunnel 不工作在 L7因此没有任何方式通知应用你应该重连到新 ztunnel。所以官方给出的现实目标是两条任意时刻任何新连接都能成功——不存在新连接被丢弃的窗口给旧 ztunnel 一段drain period让它继续处理已建立的连接。文档对此的判定是如果 drain period 长于任何一条连接的生命周期应用完全无感否则 drain period 结束时剩余连接会被强制拆掉影响程度取决于应用可能终止 in-flight 事务。SO_REUSEPORT 如何让新旧 ztunnel 同时监听同一端口新旧 ztunnel 之间交接的关键是SO_REUSEPORTztunnel默认在所有 listener 上设置该 socket 选项文档 Ztunnel Shutdown Implementation 一节。它允许同一有效 UID 的多个进程绑定同一端口详见man 7 socket之后 Linux 会把新连接分给其中任一进程——先accept()的进程赢得连接效果上等价于随机。两个进程要满足同一有效 UID这一前提而 ztunnel DaemonSet 模板 中容器以runAsUser: 0运行因此同节点的旧、新 ztunnel 天然满足该条件无需额外配置。基于这个前提一次 DaemonSet 滚动重启即文档所说upgrading to a new version, or changing some part of the DaemonSet spec的完整时序是ztunnel-new启动连接 CNICNI 把节点上所有 Pod 的当前状态发给新 ztunnel新 ztunnel 在每个 Pod 网络命名空间内建立 listener并将自身标记为 ready此时新旧两个 ztunnel 都在监听新连接会被分给任意一个随后 Kubernetes 开始终止ztunnel-old先发送SIGTERMztunnel-old捕获该信号并开始 drainingdrain 一开始ztunnel-old立即关闭自己的 listener——此后只有ztunnel-new在监听。关键不变量任何时刻都至少有一个 ztunnel 在监听ztunnel-old不再接受新连接但继续处理存量连接drain period秒后ztunnel-old强制终止仍未结束的存量连接。升级前应检查的两个配置项ztunnel chart 的 values.yaml 中有两个字段直接决定上述时序的行为升级前建议逐项核对。1. updateStrategy保证新 Pod 就绪后才动旧 Podchart 默认值# manifests/charts/ztunnel/values.yaml updateStrategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0maxUnavailable: 0意味着旧 ztunnel Pod 只在新 Pod 就绪之后才会被删除这与上面时序中先让新 ztunnel 建好全部 listener再向旧进程发 SIGTERM的交接顺序配合避免出现节点上没有任何 ztunnel 的间隙。如果你的集群里被改过这个值升级前先确认它仍满足该语义。2. terminationGracePeriodSeconds一个值两个含义chart 默认值为 30与 Kubernetes 默认一致注释明确它同时定义了两件事# manifests/charts/ztunnel/values.yaml terminationGracePeriodSeconds: 30kube 等待 ztunnel Pod 优雅退出的时间到点仍未退出就强制终止发SIGQUITztunnel 用来 drain 自身连接的时间即该值减 1 秒。DaemonSet 模板 会把该值通过环境变量TERMINATION_GRACE_PERIOD_SECONDS传给 ztunnel 容器同时写入 Pod 级的terminationGracePeriodSeconds字段二者保持同源不需要分别设置。如果你的应用存在长连接例如保持数分钟的 HBONE 隧道drain 时间不够时这些连接会在 drain 结束点被强制拆掉。文档给出的调整原则是让 drain period足够长以满足应用需求但又足够短以在 Kubernetes 强杀之前完全退出生命周期文档原文。调整时按 chart 顶部注释的说明直接设置字段本身不要走_internal_defaults_do_not_set前缀——例如用--set terminationGracePeriodSeconds你的值而不是--set _internal_defaults_do_not_set.terminationGracePeriodSeconds你的值。具体取多大文档没有给出统一数值由你按节点上最长连接的生命周期决定只需保证 drain值减 1 秒覆盖它。如何判断滚动升级是否按预期完成文档没有给出一条专用的健康检查命令但提供了可用于判断的状态点新 Pod 就绪DaemonSet 模板 为 ztunnel 配置了 readinessProbehttpGet端口15021路径/healthz/ready。新 ztunnel 建好节点上所有 Pod 的 listener 后将自己标记为 ready滚动更新才会继续推进到终止旧 Pod。不变量成立整个过程中节点上始终至少有一个 ztunnel 在监听因此新连接不会出现失败窗口。若升级期间观察到新连接被拒说明时序被破坏例如maxUnavailable被改成正数、或新 Pod 未能通过就绪检查应回到上面的时序逐步核对。旧 Pod 的退场方式旧 ztunnel 在 drain period 内结束存量连接后自行退出。如果它在 kube 的 grace period 内没退出完Kubernetes 最终会发SIGQUIT将其连同所有连接一起突然终止。这种强杀与 ztunnel 自身 drain 的区别在于无法发送 TLSclose_notify、HTTP/2GOAWAY等优雅通知文档 原文。如果你的日志里看到连接以非优雅方式中断优先检查 drain 时间是否被强杀路径抢先。边界与限制drain 机制只能保护存活期不超过 drain period 的连接更长的连接一定会在 drain 结束点被拆掉这是 L4 代理无法转移 TCP 状态的固有限制不是配置错误。ztunnel 无法通过任何方式促使应用重连到新 ztunnel存量连接的行为完全由应用自身对断连的处理决定。以上时序描述的是 ztunnel 自身升级/重启Pod 正常退出是另一场景——应用进程已退出时不需要 drainztunnel 直接拆除即可见 生命周期文档 Pod Shutdown 一节不要把两套逻辑混用。ztunnel 的整体架构与 HBONE 协议背景可参考 ztunnel 架构文档CNI 侧规则见 CNI README。【免费下载链接】istioConnect, secure, control, and observe services.项目地址: https://gitcode.com/GitHub_Trending/is/istio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考