「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
轴一:附着 / 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 排障 同一纪律:一次否证一轴。
flowchart TD
symptom["Symptom: 404 / 500 / no listener"]
symptom --> axis["Name the axis first"]
axis --> a1["status conditions"]
axis --> a2["empty or wrong XdsIR"]
axis --> a3["xDS NACK stale snapshot"]
axis --> a4["Envoy dataplane"]
axis --> a5["east-west after hop"]
| 轴 | 触发选轴的症状 | 先查 | 不要先做 |
|---|---|---|---|
| 一 | 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 示例是文档原样,不是本机复现。
→ 上一篇:运维与升级 · 系列目录 · 下一篇:对照替代路径
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Envoy Gateway】南北向全景:缺口、五轴坐标系与 16 篇路线
相对 Gateway API 产品教程、Cilium 南北向边界、Envoy 消费侧与 istiod 翻译,钉清 Envoy Gateway v1.9.0 控制面内核缺口;定义附着/status、IR、xDS、Envoy 数据面、入口之后东西向五条轴,给出 16 篇阅读路线。
Envoy Gateway / Gateway API:从 CR 附着到 xDS
补齐站内 Gateway API 产品教程与 Envoy 数据面消费侧之上的南北向控制面内核:附着与 status、Provider watch、IR 翻译、xDS 与 Infra、路由/TLS/L4/Policy 边界,并以排障与相对 Cilium Gateway / Istio / Ingress 的选型收束。
【Envoy Gateway】Gateway API Translator 与 IR:对象如何变成 XdsIR / InfraIR
钉清 Envoy Gateway v1.9.0 为何用中间表示解耦 Gateway API 与 Envoy 资源树:XdsIR 与 InfraIR 的分工、Translate 的顺序与依赖,以及 status 为何必须在同一次翻译里计算。
【Envoy Gateway】xDS Translator 与 Infra:推送不等于在服务
把 XdsIR 钉到 LDS/RDS/CDS/EDS/SDS,把 InfraIR 钉到 Envoy 舰队;说明 go-control-plane Delta xDS 只保证快照送达,不能代替 Envoy warming 与 ACK。