ZTunnel 更新过程
ZTunnel 工作在 OSI 模型的第 4 层(L4):它代理 TCP 字节流,并且无法感知其上方的应用协议。因此,已建立的 TCP 连接无法从一个 ZTunnel 进程交接给它的替代进程。由于 ZTunnel 作为按节点(per-node)的 DaemonSet 运行,对它进行替换时,至少会一次影响一个节点上的所有 mesh 流量。了解这种滚动更新行为有助于你为依赖长连接的工作负载规划更新。
滚动更新阶段
默认情况下,ZTunnel DaemonSet 使用 RollingUpdate 策略,并且一次处理一个节点。在每个节点上,替换过程会经历以下阶段:
- 启动 — 新的 ZTunnel pod 启动,而旧的 pod 继续提供流量服务。
- 就绪 — 新的 ZTunnel 在该节点上的每个 pod 中建立监听器并报告就绪。两个实例会短暂地并行运行,并且由于 ZTunnel 使用
SO_REUSEPORT,在这段时间内任意一个实例都可能接受新的连接。 - 排空 — Kubernetes 向旧的 ZTunnel 发送
SIGTERM,旧实例会立即关闭其监听器并开始排空。从这一刻起,只有新的 ZTunnel 接受连接;在任何时刻,该节点都不会处于没有监听中的 ZTunnel 的状态。 - 连接处理 — 旧的 ZTunnel 继续为其已经持有的连接提供服务。
- 终止 — 当
terminationGracePeriodSeconds定义的排空期限到期时,旧的 ZTunnel 会强制关闭任何仍处于打开状态的连接。
任何存活时间超过排空期限的连接都会被重置。下面两节分别介绍如何延长该期限,或者完全避免强制重置。
配置优雅的连接终止
最简单的缓解方式是将 terminationGracePeriodSeconds 调高到足以让应用的连接在排空阶段自然完成。要选择合适的值,需要了解 mesh 中各工作负载的连接生命周期。请记住,DaemonSet 一次只处理一个节点,因此取值过大也会拉长整个集群更新的持续时间——应尽量选择一个平衡的设置。
在 ZTunnel 自定义资源(CR)中设置该值:
- 本示例中为五分钟——请根据你需要保护的最长连接生命周期来调整该值。
实现了重试逻辑或使用较短 keepalive 超时时间的应用,相比于持有非常长的空闲 TCP 连接的应用,在 ZTunnel 重启后恢复得要优雅得多。
通过排空节点安全更新 ZTunnel
由于 TCP 连接无法在 ZTunnel 进程之间转移,将应用迁移到新的 ZTunnel 的唯一可靠方式,是优雅地重启应用本身。排空节点可以以受控方式实现这一点:应用会按照各自的终止宽限期关闭,空节点上的 ZTunnel 会在没有任何流量风险的情况下完成替换,而应用在恢复后会通过新的 ZTunnel 重新连接。
操作步骤
-
将 ZTunnel DaemonSet 切换为
OnDelete更新策略,这样只有在你删除旧 pod 之后才会创建新的 pod:- 使用
OnDelete时,更新ZTunnel资源本身不会自动替换任何正在运行的 pod;每个节点只有在你删除其 ZTunnel pod 时才会更新。
- 使用
-
将
ZTunnelCR 的spec.version字段设置为目标版本。 -
排空一个节点。所有应用会迁移到其他节点,并在各自的
terminationGracePeriodSeconds约束下优雅关闭其长连接。 -
删除已排空节点上的旧 ZTunnel pod,并等待新的 pod 启动。由于节点上不再保留任何工作负载,因此此次替换不会对流量造成风险。
-
将该节点重新标记为可调度。重新落到该节点上的工作负载会自动使用新的 ZTunnel。
-
对集群中其余每个节点重复步骤 3 到 5。
其他资源
- 排查 ZTunnel(Istio 文档)
- 排查 waypoint proxies(Istio 文档)