原文发布于 quant67.com,转载请保留出处。
「HTTPRoute 已经 apply,为什么还是 404?」与「status 看起来绿,为什么 Envoy 仍走旧路由?」很少落在同一层。前者可能是 parentRefs 未附着、ResolvedRefs 为假、或同 listener 上另一条规则把匹配阴影掉;后者可能是 xDS NACK 后代理停在上一份 known-good,或 Worker 还没 warming 完。若一上来改 HTTPRoute YAML 或重装控制器,因果链会被冲掉,还可能把可恢复的 status 写成「网关坏了」。
本文是系列第 13 篇:按五轴 映射症状。口诀与第 01 篇相同:先点名轴,再下钻模块 。status 语义见第 02 篇;IR 见第 04 篇;xDS 与舰队见第 05 篇。无真实 Envoy Gateway 集群则不粘贴伪造 egctl、Route status 或 config_dump。
本文是「Envoy Gateway / Gateway API」系列第 13 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 12 篇 · 运维与升级 Helm/CRD 分装、VAP、存储版本 第 13 篇 · 排障坐标系 五轴归因 第 14 篇 · 对照替代路径 Cilium Gateway / Istio / Ingress
版本锚定 :Envoy Gateway v1.9.0 (源码 tag v1.9.0 ,2026-08-14)。文档钉
gateway.envoyproxy.io/v1.9/。Gateway API v1.6.1 ;数据面 Envoy v1.39.0 。官方 Configuration Issues 、Gateway Exported Metrics 、v1.9.0 Release Notes(xdsNACKTotal/RouteRulesOverlap)为 A 级入口。清单是工程方法,不是一次已跑通的排障故事。
一、口诀:先点名轴,再动 YAML
text
轴一:附着 / status --- Accepted / Programmed / ResolvedRefs / RouteRulesOverlap
轴二:IR --- Gateway API Translator 产出的 XdsIR / InfraIR
轴三:xDS --- xDS Translator、go-control-plane、NACK、快照未送达
轴四:Envoy 数据面 --- Filter / cluster / warming(外链 envoy/15)
轴五:入口之后东西向 --- 出 Envoy 之后的 CNI;指针到第 15 篇
每轴固定三列:症状 → 先查什么 → 不要先做什么 。与 Cilium 排障、Tetragon 排障 同一纪律:一次否证一轴。
| 轴 | 触发选轴的症状 | 先查 | 不要先做 |
|---|---|---|---|
| 一 | YAML 已 apply,条件未绿;跨 ns 引用被拒;同 listener 阴影 | status.conditions / status.parents,核对 observedGeneration |
先改 path 碰运气;先重装控制器 |
| 二 | status 看似可接受,IR 无对应 Listener/Route | Translator 是否吃进该对象;egctl x translate --to ir 的语义(不伪造输出) |
把「Accepted=True」写成「数据面已有这条路由」 |
| 三 | NACK、大集群重连后停在旧配置、xds_nack_total 上升 |
xDS 流、消息上限、上一份 known-good | 先改业务重试;先扩 Envoy 副本「冲掉」 |
| 四 | 监听器在、上游耗尽、证书/协议错、503 与 warming | envoy/15 五轴 | 在控制面 YAML 上循环,不看 Worker 快照 |
| 五 | Gateway 已 200,后端互调失败或跨节点黑洞 | 交回 Cilium 五轴与四元组;见第 15 篇 | 用南北向 status 解释 Hubble deny |
默认入口顺序 (可裁剪):GatewayClass / Gateway / Route 的 status →(条件绿仍无流量)问 IR 是否为空 →(IR 有对象)问 xDS 是否 ACK →(ACK 了)问 Envoy 数据面 →(已出网关)问东西向。官方 Troubleshooting and Status 的第一句纪律是:排障 Gateway API 对象时,先看 status.conditions。
图「症状如何落到五条轴」对应上表:选轴是分诊,不是结论。轴一未否证之前,不要把工单写成轴四。
二、轴一:附着与 status
症状
- Route 已 apply,流量 404,或根本打不到监听器。
- Gateway
Programmed为假;RouteAccepted为假;ResolvedRefs为假。 - 条件看起来「有 True」,但
observedGeneration对不上metadata.generation。
规范钉(不是实现口号)
Gateway API 把状态写成正极性 Conditions(GEP-1364;概念页 Troubleshooting and Status):
| 条件 | 规范含义 | 排障含义 |
|---|---|---|
Accepted |
语义/句法可接受,会产生某些数据面配置,且被控制器接受 | 不等于整份 YAML 都合法,也不等于已推到 Envoy |
Programmed |
已解析并已送给数据面,「很快」就绪;「很快」由实现定义 | 不等于 Envoy Worker 已在服务新快照 |
ResolvedRefs |
对象内引用都存在且合法 | 为假时仍可能 Accepted=True------部分配置已生效 |
RouteRulesOverlap |
v1.9.0 新增的警告:同 listener 上匹配条件完全相同 | 阴影路由;404/打到另一条后端时先看它 |
GEP-1364 把 Programmed 从旧的 Ready 里拆出来,明确写了:该条件不 声明数据面此刻已就绪,只声明配置已送出。把 Programmed=True 当 SLO「流量已按新规则走」,是把规范里的「soon」读成了秒表。
另一条规范陷阱:scope 。实现只能给「能从自己拥有的 GatewayClass 串起所有权链」的对象写 status。parentRef 指到一个它不负责的 Gateway 时,不会出现一条「你指错了」的条件------对象可能干脆没有 parents status。排障时「没有 status」与「Accepted=False」不是同一格。
核对路径
条件是否过期 :observedGeneration 必须等于 metadata.generation。对不上,status 是旧世代;原因可能是控制器没追上,或对象已离开该实现的 scope。
Gateway :Accepted 问的是 GatewayClass / listener 是否被本控制器认领;Programmed 在 Envoy Gateway 里还叠了 Infra Manager 拉起的 Deployment/Service。v1.9.0 Release Notes 修过一类误报:无云 LB 的裸金属上 LoadBalancer Service 没有 ingress,却有 spec.externalIPs 时,曾报 Programmed: False / AddressNotAssigned。排障时要读 reason,不要只看 type。
Route :看 status.parents[],不是只看资源级摘要。官方 v1.9 Configuration Issues 给出的对照示例是:HTTPRoute Accepted=True 且 ResolvedRefs=False(BackendNotFound) ------后端 Service 不存在。该文档同时写明:配置未被接受时,Envoy Gateway 会给受影响路由赋 direct_response,客户端拿到 HTTP 500 ,access log 里 response_code_details 为 direct_response。这是轴一的典型出口,不是轴四「上游 503」。
跨 namespace :没有 ReferenceGrant 时,跨 ns 的 backendRefs / Secret 会在 ResolvedRefs 上失败。不要先怀疑 IR。
阴影 :v1.9.0 为「同 listener 上匹配条件完全相同」的路由加 RouteRulesOverlap 警告。匹配更宽的规则把更具体的规则盖住,表象常是 404 或打到错误后端;先读警告条件,再谈「Envoy 路由表坏了」。机制见第 06 篇。
L4 静默消失 :v1.9.0 只 reconcile gateway.networking.k8s.io/v1 的 TCPRoute/UDPRoute。未装 Gateway API v1.6 CRDs 时,官方破坏性变更写的是静默跳过 ,不是 500。对象可能还在 etcd 里,但不进翻译输入集------看起来像「没 status / 没流量」,根因在第 08 篇 与第 12 篇 的 CRD 所有权,仍属轴一的「对象未进入本控制器 scope」。
Policy 未生效 :v1.9.0 起 SecurityPolicy / BackendTrafficPolicy 的 mergeType 只能挂 xRoute ;挂 Gateway / ListenerSet 父资源会被 admission 拒绝。Lua EnvoyExtensionPolicy 默认关闭 ,需 enableLua。策略 YAML 还在,并不等于进了 IR。见第 09 篇。
不要先做 :删掉所有 HTTPRoute「验证网络」;把 500 direct_response 写成「后端挂了」;把无 status 的 Route 当成控制器 bug,而不核 parentRef 是否 in-scope。
官方 CLI 入口是 egctl x status all -A(Use egctl / Configuration Issues )。本文不粘贴未在本环境执行的表格。kube-state-metrics 可把同类条件变成大规模扫描,口径见第 11 篇。
三、轴二:IR
症状
- 轴一条件已经能讲通「对象被接受」,但流量仍像没有这条 Listener/Route。
- 改了 Policy / EnvoyPatchPolicy,status 不报错,数据面行为不变。
- 怀疑 Translator 把对象翻译成了空的或错误的 XdsIR。
机制回顾
官方 System Design 把动态配置收成两份中间表示:Translator(internal/gatewayapi 的 Translator)输出 XdsIR (给 xDS Translator)和 InfraIR (给 Infra Manager)。Gateway API Translator Design 写明:每一步既可能写 IR,也可能写 status。IR 存在的理由是把 Gateway API 与 Envoy 资源树解耦------排障多一跳,是设计税,不是事故。
轴二要否证的问题只有一句:这份 Gateway API 对象有没有变成 Translator 认为应该下发的那棵 IR? status 绿只证明 Translator 计算过条件;IR 空证明「计算的结果是不生成对应 Listener/Route」。两件事可以同时发生,例如:listener 因证书引用失败而未编程,v1.9.0 已把「listener 未 Programmed」与「Route Accepted」拆开------Route 仍可 Accepted,IR 里却没有那条 HTTPS 链。
核对路径
输入集 :对象是否在 Kubernetes Provider 的 watch 里?漏装 CRD、namespace-scoped watch 未包含控制器自己的命名空间、条件 watch 因集群 CRD 子集而跳过(v1.9.0 为 GKE/OpenShift 一类「缺 ListenerSet / BackendTLSPolicy」的包做了条件 watch)------对象不会进 Translator。这与轴一的 scope 相邻,但根因是 Provider,不是 Route YAML。见第 03 篇。
翻译命令语义 :官方 egctl x translate 可以把 Gateway API 译成 --to ir 或 --to xds(Use egctl)。这是轴二与轴三的分界工具:IR 空而 xDS 也空,停在轴二;IR 有对象而 Envoy 无对应资源,进入轴三。本文不伪造任何 translate 输出。
Policy / Patch 匹配旧名 :v1.9.0 多处破坏面是「xDS 资源改名,EnvoyPatchPolicy 仍匹配旧键」------JWT provider 名、DNS cluster typed config、Lua filter 名、system_ca_certificates 共享 SDS secret、共享限流从 route.rateLimits 挪到 typedPerFilterConfig。Patch 还在,IR/xDS 里的目标已经改名,表象是「策略写了不生效」。这是轴二/三交界,先核 Release Notes 的字段搬家,再谈 Filter 链。
不要先做 :把 DeepWiki 或 /latest/ 文档里的 IR 字段当成 v1.9.0;在无 dump 时用想象中的 Listener 名写结论。
轴二出口:IR 里明确没有该 Listener/Route,就不要进轴四改 Envoy 日志级别。
四、轴三:xDS
症状
- IR 或 translate-to-xds 语义上已有资源,Envoy 仍服务上一份配置。
- 控制面指标里 NACK 上升;或大集群 Envoy 重连后配置不再更新。
机制钉
xDS Translator 把 XdsIR 编成 LDS/RDS/CDS/EDS/SDS,经 go-control-plane 的 Delta xDS 送给 Envoy。v1.9.0 新增 xdsNACKTotal:NACK 是带 ErrorDetail 的 DiscoveryRequest,表示 Envoy 拒绝了 上一份更新;指标按 node ID 与 resource type URL 打标。Prometheus 导出名为 xds_nack_total(Gateway Exported Metrics)。
NACK 之后的数据面语义,站内 envoy/09--11 已经写过:ACK 表示「这份资源孤立看来合法、意图应用」,不等于依赖树 warming 完、流量已切。Envoy 在拒绝后常停在上一份 known-good。控制面「已推送」与「正在服务」在这一轴上再次分裂。
v1.9.0 把 xDS gRPC 默认接收上限从 4MiB 提到 32MiB (xdsServer.maxReceiveMessageSize)。官方原因:大规模下 Envoy 重连时的 delta 请求可能超过 4MiB,流以 "received message larger than max" 断开,代理留在最后一份 known-good。这是轴三的容量故障,不是 Route 写错。
同轴还要看:快照是否创建/更新(xds_snapshot_create_total / xds_snapshot_update_total)、流是否还在(xds_stream_duration_seconds)。有 snapshot 更新而无 ACK,优先查 NACK 而不是再 apply 一次 YAML。
核对路径
先读 type URL :NACK 打在 Listener 还是 Cluster/Secret,决定回到第 07 篇(SDS unix://、证书链)还是第 05 篇 的资源树。
GatewayNamespaceMode :v1.9.0 修过该模式下 xDS 认证绕过,并给 SotW 请求做校验。认证失败的表象是「推不动」,容易被写成轴二。安全更新见第 10 篇 与第 12 篇。
不要先做:把 NACK 当成「改副本数就能好」;把 4MiB 时代的 runbook 原样用在 v1.9.0 默认 32MiB 上却不核实际设置。
轴三出口:拿到 type URL 与 NACK/上限证据后,若资源已 ACK 仍行为不对,才进轴四。
五、轴四:Envoy 数据面
本轴不在本系列展开 。监听器已在、cluster 空、SDS 未 warming、Hot restart drain、连接池溢出、RESPONSE_FLAGS,全部使用 Envoy 数据面第 15 篇 的五条坐标:请求路径、线程快照、匹配改写、xDS 一致性、上游资源。版本钉 Envoy v1.39.0。
Envoy Gateway 只提供进入该方言的入口:
- 官方 Envoy Proxy Admin Interface :admin 在 19000,绑 localhost,需对对应 Gateway 的 Envoy Deployment 做 port-forward;应用开发者未必有数据面命名空间权限。
egctl config envoy-proxy可取正在跑的 xDS 视图(官方示例含 route dump)。本文不粘贴未执行输出。- access log / metrics / tracing 能证明哪一轴,见第 11 篇。记住 v1.9.0 tracing client sampling 默认 0%:没有 span 不等于没开 tracing。
不要先做:在轴一至三未否证时改 HCM 超时;把 Envoy 503 一律写成「Gateway 控制器 hang」。
轴四出口:数据面已按当前快照正确服务,请求仍在后端失败,进入轴五。
六、轴五:东西向(指针到第 15 篇)
Gateway 返回 200 之后,包成为集群内的东西向流。失败可能是 identity 策略、Service BPF、加密路径,而南北向五轴全绿 。把 Hubble Policy denied 写进 HTTPRoute 工单,或反过来用 Gateway status 解释跨节点黑洞,都会污染坐标系。
本篇只留口令:出了 Envoy Gateway 的 hop,换一套轴,不要扩写本篇的 status/IR/xDS。 北段/南段证据包、两套口令、CNI/KPR/加密/Gateway 四元组,在第 15 篇 回收 Cilium 15。本系列不重写 identity/map。
七、谱系、争论与开放问题
排障五轴走在编译器诊断传统上:先把失败钉到阶段 (附着、中间表示、代码生成、运行时、下游环境),再打开该阶段的工具。Gateway API 把「配置已生效」拆成 Accepted / Programmed / ResolvedRefs(GEP-1364),就是在规范层拒绝单一 Ready。Envoy Gateway 再插入 IR 与 xDS 两跳,值班若把所有 404 写成「路由写错」,等于丢掉阶段名。
争论不在「要不要 status」,而在 status 绿是否足以当 SLO :轴二、轴三可以在条件看似成立时仍让流量走空 IR 或旧快照。开放问题交给第 16 篇:IR 对账是否一等公民、xds_nack_total 能否进发布门禁。
参考资料
规范 / 官方文档 / 源码(A)
- Gateway API Troubleshooting and Status :
Accepted/Programmed/ResolvedRefs、observedGeneration、scope - GEP-1364:Status and Conditions Update(
Programmed相对Ready) - Envoy Gateway v1.9.0 Release Notes:
xdsNACKTotal、RouteRulesOverlap、TCP/UDPv1静默跳过、mergeType仅 xRoute、xDS 默认 32MiB - Configuration Issues (
gateway.envoyproxy.io/v1.9/troubleshooting/configuration/):Accepted 与 ResolvedRefs 分叉、direct_response500 - Gateway Exported Metrics :
xds_nack_total等 xDS Server 指标 - Use egctl :
egctl x status、egctl x translate --to ir/--to xds - System Design / Gateway API Translator Design:XdsIR、InfraIR、status 在翻译中计算
- tag v1.9.0 :
internal/gatewayapiTranslator、internal/ir
站内对照
- 系列目录
- 第 02 篇 · 附着与 status
- 第 04 篇 · IR Translator
- 第 05 篇 · xDS 与 Infra
- 第 11 篇 · 可观测
- Envoy 15 · 数据面排障
- Cilium 13 · 东西向五轴
实验台账
- 无本环境 Envoy Gateway 集群;不粘贴
egctl/config_dump。官方 Configuration Issues 的 status / 500 示例是文档原样,不是本机复现。
→ 上一篇:运维与升级 · 系列目录 · 下一篇:对照替代路径