土法炼钢 · 系统与基础设施

【Envoy Gateway】L4 路由:不升 v1.6 CRDs,TCP/UDP 会静默消失

文章导航

分类入口
kubernetesnetwork
标签入口
#envoy-gateway#tcproute#udproute#tlsroute#gateway-api#storage-version#v1.9.0

目录

升 Envoy Gateway 到 v1.9.0 却仍使用旧 Gateway API CRDs 时,TCPRoute / UDPRoute 不会改成返回 HTTP 500,控制器也不保证弹一条「请升级 CRD」的错误来提醒你。发行说明写的是:gateway.networking.k8s.io/v1 reconcile;若未安装 v1.6 CRDs,这些路由被静默跳过。 数据库、DNS、游戏隧道的入口会变成「端口听着、没有后端」,像防火墙,不像应用故障。

本文只钉版本门:v1.6 里三种 L4/L7-ish Route 的 API 版本、EG v1.9 只盯 v1、standard 与 experimental channel 对 v1alpha2 的差异、以及失败表象。不把「控制器会报错提醒」写成 v1.9 保证。存储版本迁移的运维步骤与 Helm 分装见第 12 篇。

本文是「Envoy Gateway / Gateway API」系列第 8 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 7 篇 · TLS / SDS 两层 TLS 与 SDS 破坏面
第 8 篇 · L4 路由 v1 reconcile;CRD 未升则静默跳过
第 9 篇 · Policy attachment 五类 Policy 与 mergeType

上一篇TLS / SDS · 下一篇Policy attachment

版本锚定:Envoy Gateway v1.9.0 Release Notes 破坏性变更;Gateway API v1.6.1 CRD(standard / experimental 的 served/storage 字段已核 raw YAML);TLSRoute 自 v1.5.0 起已在 Standard 且为 v1。实验台账:未跑


一、TCPRoute / UDPRoute / TLSRoute 在 v1.6 的 API 版本

Gateway API v1.6.0(2026-06-30)把 TCPRoute、UDPRoute 从 Experimental 推到 Standard,API 版本改为 v1v1alpha2 自该版本起 deprecated,将来删除。Kubernetes 博客与 GEP-2644 / GEP-2645 把它们定义成:只按协议与端口转发,没有 HTTP 层。

TLSRoute 更早:Gateway API 文档写 Standard Channel since v1.5.0,资源已是 gateway.networking.k8s.io/v1。它按 TLS 握手的 SNI 选后端,可 Passthrough 或 Terminate,不是「又一个 TCPRoute」。

资源 进入 Standard v1.6.1 推荐 apiVersion 匹配面
TLSRoute v1.5.0 gateway.networking.k8s.io/v1 SNI hostname(字段必填)
TCPRoute v1.6.0 gateway.networking.k8s.io/v1 listener 协议 TCP + 端口;无 L7
UDPRoute v1.6.0 gateway.networking.k8s.io/v1 listener 协议 UDP + 端口;无 L7

TCPRoute 只能挂 protocol: TCP 的 listener;挂到 HTTP/HTTPS 上不会被接受。UDP 同理。规范允许同一端口上 TCP 与 UDP listener 并存(例如 DNS 53)。Kubernetes 博客里的最小例子:Gateway listener protocol: TCP + allowedRoutes.kinds: TCPRoute,TCPRoute parentRefs.sectionName 指向该 listener,backendRefs 给出 Service 端口。省略 sectionNameport 时,路由附着到该 Gateway 上每一个 TCP listener——比 HTTPRoute 更容易「一条 Route 打到多个端口」,升级或复制 Gateway 时要核对。

GEP-2644 写明 TCPRoute 补的是 HTTPRoute/TLSRoute 盖不住的那类 TCP 工作负载(非 HTTP 的 TLS 数据库、纯 TCP)。它几乎没有匹配算法:没有 path,没有 header。版本门因此比匹配门更致命——对象一旦没进 informer,翻译器没有「部分匹配失败返回 404」可报。该 GEP 把 Standard 毕业条件写成:列出 feature name TCPRoute、补齐 conformance 场景、至少三份实现提交通过报告。v1.6 宣布毕业,并不自动改写集群里已经 applied 的 v1alpha2 清单。

EG v1.9 TCP routing 任务演示:Gateway 上两个 TCP listener(8088 / 8089),两条 TCPRoute 用 parentRefs.sectionName 分别附着。该任务页示例仍写 apiVersion: gateway.networking.k8s.io/v1alpha2 这与同版本 Breaking notes 以及 standard-channel CRD 的 served: false 不一致,应视为文档滞后。照抄到只装了 v1.6.1 standard CRDs 的集群时,apiserver 不会再服务 v1alpha2(第三节)。新清单应使用 v1

TLSRoute 的 Terminate 与 TCPRoute 的差别见第 7 篇:后者不看 SNI,一条 listener 对一个后端;前者按 SNI 扇出。Passthrough 则根本不在网关终止 TLS。


二、EG v1.9 只 reconcile v1

v1.9.0 Breaking changes 原文:

Envoy Gateway now reconciles TCPRoute/UDPRoute via the gateway.networking.k8s.io/v1 API. You must upgrade the Gateway API CRDs to v1.6 with this release. Existing v1alpha2 manifests continue to work (both versions are served), but if the v1.6 CRDs are not installed, TCP/UDP routes will be silently skipped. The stored version moves to v1; a storage-version migration will be required before v1alpha2 is eventually removed.

拆成三条互不替代的事实:

  1. 控制器 watch 的是 v1 集群里若只有旧的 v1alpha2 CRD、没有 v1.6 的 v1,EG 看不到这些对象,翻译输入集为空。这就是「静默跳过」:不是 NACK,不是 HTTPRoute 那种 404 业务响应。
  2. 「现有 v1alpha2 manifest 仍可用、两个版本都 served」 描述的是 已经装上 v1.6、且 channel 仍服务 v1alpha2 的情况(实验频道 CRD,见第三节)。不能理解成「永远不用改 yaml」。
  3. 存储版本改为 v1。 对象若仍以 v1alpha2 为 storage version,在未来 CRD 去掉该版本之前必须做存储版本迁移(Gateway API CRD Management 指南;工具如 kube-storage-version-migrator)。第 12 篇展开,本篇只点名风险。

EG 对「CRD 根本不存在」另有一条长期策略:TCPRoute/UDPRoute 等 watch 在 CRD 缺失时跳过,避免整控制器 crash-loop(历史 issue #3387 一类;v1.9 还把 ListenerSet、GRPCRoute、BackendTLSPolicy 做成存在性检查)。跳过启动失败 ≠ 在 status 里提醒你 L4 没了。 egctl x status 在 v1.9 也改为:缺 CRD 时静默跳过,或 -v 时打到 stderr。排障信号可能是「工具没列出 TCPRoute」,不是一条醒目的 Failed condition。

因此升级检查单的第一项不是 curl HTTP,而是:Gateway API CRDs 是否已到 v1.6.x,且 TCPRoute/UDPRoute 的 v1 是否 served。 Helm 只升 gateway-helm--skip-crds 留着旧 CRD,正好踩进这个门。


三、standard vs experimental channel 与 v1alpha2 停服风险

Gateway API 用 release channel 而不是 SemVer 单独表达稳定性。Standard 的版本删除分四步(官方 CRD Management):新版本成为 storage → 旧版本 deprecated → 旧版本不再 served 但仍留在 CRD 里做转换 → 彻底从 CRD 去掉。

v1.6.1 的 TCPRoute CRD,本仓库核过 GitHub raw YAML:

Channel 文件 v1 v1alpha2
standard config/crd/standard/gateway.networking.k8s.io_tcproutes.yaml served: truestorage: true served: falsestorage: false,带 deprecationWarning
experimental config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml served: truestorage: true served: truestorage: false

这把发行说明里「both versions are served」钉到 experimental channel。Standard channel 在 v1.6.1 已经走到「v1alpha2 不再 served」。manifest 若仍写 apiVersion: gateway.networking.k8s.io/v1alpha2

UDPRoute 的 standard CRD 已同样核过 tag v1.6.1 config/crd/standard/gateway.networking.k8s.io_udproutes.yamlv1served: true / storage: truev1alpha2served: false / storage: false,与 TCPRoute 一致。

Experimental channel 还可能包含尚未毕业的资源,且允许更剧烈的破坏。平台若声明「只用 standard」,就不能靠 experimental 的双版本 served 来拖延改 yaml。

flowchart TD
  subgraph crds["Gateway API CRDs"]
    old["pre-v1.6 TCPRoute v1alpha2 only"]
    std["v1.6.1 standard"]
    exp["v1.6.1 experimental"]
  end
  watch["EG v1.9 watches gateway.networking.k8s.io/v1"]
  old -->|"no v1 API"| skip["routes silently skipped"]
  std -->|"v1 served"| ok["v1 manifests translated"]
  std -->|"v1alpha2 served false"| noserve["manifests must be v1"]
  exp -->|"v1 and v1alpha2 served"| conv["v1alpha2 apply; stored as v1"]
  watch --> skip
  watch --> ok
  conv --> watch

图:CRD 版本与 channel 决定对象会不会进入 EG 的 v1 reconcile。静默跳过发生在「EG 已升、CRD 未到 v1.6」这一格。


四、失败表象:不是 HTTP 500,是无流量

L4 没有「路径写错返回 404」这种应用语义。TCPRoute 没进翻译,Envoy 侧对应 listener 要么不存在、要么挂着第 5 篇提到的空 EmptyCluster。客户端看到的是连接失败、超时、RST,或端口通了但协议无响应——取决于还有没有其它 listener 占用该端口。UDP 更不容易从应用日志里看出「网关没挂上」:报文直接消失,没有 TCP 握手可抓。

对照:

HTTPRoute 常见表象 TCPRoute 未翻译时
应用 404 / 500 / UNIMPLEMENTED 没有 HTTP 状态码
Route status Accepted / ResolvedRefs / Overlap 可能根本没有 v1 对象可写 status;旧 v1alpha2 对象停在 EG 视野外
控制器 通常仍 Running 仍 Running;不保证因缺 v1 CRD 而 CrashLoop
数据面 RDS 缺 host LDS 缺 TCP listener 或空 cluster

所以值班口令不能是「看有没有 5xx」。应先问:这是不是 TCP/UDP 入口、CRD channel 与版本、EG 是否在 watch v1。再用第 5 篇的 Infra/xDS 轴确认舰队与快照。

可操作的语义检查(本篇未跑,不粘贴输出):

  1. CRD:TCPRoute / UDPRoute 是否存在 v1,standard 安装下 v1alpha2 是否已 served: false
  2. 清单:apiVersion 是否已改为 gateway.networking.k8s.io/v1。仍写 v1alpha2 时,在 standard v1.6.1 上会在 apiserver 被拒,而不是「EG 帮你转换」。
  3. 存储:升级前是否已把旧对象迁到 v1 storage(否则将来删版本时硬挡)。
  4. 对照:同集群 HTTPRoute 仍工作,不能证明 L4 也被 reconcile。

v1.9 文档与 notes 没有承诺:「缺 v1.6 CRDs 时控制器会 Error 提醒」。相反,notes 用了 silently skipped;egctl 对缺 CRD 也是 skip。把「会报错」写成保证,会让 runbook 在最需要信号的时候去等一条永不出现的事件。

TLSRoute 不在这次「升 v1 才 reconcile」的同一句话里。它已是 v1 Standard。L4 升级事故的主因是 TCP/UDP 与 CRD 频道,不是 TLSRoute 突然改组。

存储版本:若对象仍记着 v1alpha2 storage,将来 CRD 去掉该版本时升级会硬挡(Gateway API 指南中 GatewayClass 的历史例子)。v1.9 notes 要求在 v1alpha2 最终删除前完成迁移。这是未来删除的门,与「现在静默跳过」是两件事:现在跳过是因为 EG 不 watch 旧 API;将来挡升级是因为 etcd 里还躺着旧 storage version。


五、谱系、争论与开放问题

谱系

Kubernetes Service / NodePort / Ingress TCP 注解(不可移植)
  → Gateway API 实验频道 TCPRoute/UDPRoute v1alpha2
  → GEP-2644 / GEP-2645 补全毕业条件与一致性测试
  → v1.6 Standard + v1;CRD channel 决定 served 集合
  → EG v1.9:控制器只 reconcile v1;与 CRD 升级解耦则静默无流量

L4 路由的学术/规范问题不是匹配算法(几乎没有 L7 匹配),而是 API 生命周期:alpha 版本如何从 served 集合里拿掉,而不把现有对象留在控制器视野外。Gateway API 用 channel + 四步删版本回答;EG 用「watch v1 + 缺 CRD 则跳过」回答控制器存活。两者叠加,用户可见性最弱。

争论:静默跳过 vs 启动失败

A 侧(EG 实现选择):托管集群常只装 Gateway API 子集(GKE addon 缺 ListenerSet 等)。缺一种 CRD 就 crash-loop,爆炸半径是整个南北向。跳过让 HTTP 入口仍活。

B 侧(运维):TCP 入口消失且无 Error,平均定位时间上升。正确性要求至少有一条 Ready/Degraded 条件说「TCPRoute CRD 不是 v1」。

v1.9 发行说明站在 A 侧写事实。本系列要求 runbook 显式检查 CRD,而不是等待控制器良心发现。

开放问题

  1. 控制器能否在仍 Running 时对 Gateway 打出「L4 CRD 版本不匹配」条件,而不违反「缺 CRD 不崩溃」?可检验:装 v1.5 CRDs + EG v1.9,看 status 是否出现任何非静默信号(本文未跑)。
  2. Standard channel 已 served: false 时,发行说明「both versions are served」容易误导只读 notes、不看 CRD YAML 的升级者。文档与 notes 的 channel 分叉如何收敛?
  3. 与第 12 篇交接:storage-version migrator 是否应成为 EG 升级 chart 的硬依赖,而不是独立工具。

六、小结

  1. v1.6 起 TCPRoute/UDPRoute 为 Standard v1;TLSRoute 已是 v1。EG v1.9 按 v1 reconcile。
  2. 未装 v1.6 CRDs:L4 路由静默跳过,不是 500,也不是保证有的控制器 Error。
  3. v1.6.1 standard TCPRoute:v1alpha2 不再 served;清单必须改 v1experimental 仍可 served v1alpha2,存储为 v1。
  4. 失败表象是无流量 / 连不上;先查 CRD 版本与 channel,再查 IR/xDS。

下一篇进入 Policy:SecurityPolicy 等如何挂到 Route,以及 v1.9 mergeType 为何不能再挂 Gateway。


七、参考资料

规范 / 官方文档(A)

源码 / CRD YAML(A)

核心论文 / 规范传统

实验 / 工具

站内对照


上一篇:TLS / SDS · 系列目录 · 下一篇:Policy attachment

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .