Envoy Gateway 排障:未 Accepted、空 IR、xDS NACK 与旧快照

原文发布于 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 IssuesGateway 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 排障 同一纪律:一次否证一轴

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 为假;Route Accepted 为假;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。

GatewayAccepted 问的是 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=TrueResolvedRefs=FalseBackendNotFound ------后端 Service 不存在。该文档同时写明:配置未被接受时,Envoy Gateway 会给受影响路由赋 direct_response,客户端拿到 HTTP 500 ,access log 里 response_code_detailsdirect_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 / BackendTrafficPolicymergeType 只能挂 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 -AUse egctl / Configuration Issues )。本文不粘贴未在本环境执行的表格。kube-state-metrics 可把同类条件变成大规模扫描,口径见第 11 篇


三、轴二:IR

症状

  • 轴一条件已经能讲通「对象被接受」,但流量仍像没有这条 Listener/Route。
  • 改了 Policy / EnvoyPatchPolicy,status 不报错,数据面行为不变。
  • 怀疑 Translator 把对象翻译成了空的或错误的 XdsIR。

机制回顾

官方 System Design 把动态配置收成两份中间表示:Translator(internal/gatewayapiTranslator)输出 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 xdsUse 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 是带 ErrorDetailDiscoveryRequest,表示 Envoy 拒绝了 上一份更新;指标按 node ID 与 resource type URL 打标。Prometheus 导出名为 xds_nack_totalGateway Exported Metrics)。

NACK 之后的数据面语义,站内 envoy/09--11 已经写过:ACK 表示「这份资源孤立看来合法、意图应用」,不等于依赖树 warming 完、流量已切。Envoy 在拒绝后常停在上一份 known-good。控制面「已推送」与「正在服务」在这一轴上再次分裂。

v1.9.0 把 xDS gRPC 默认接收上限从 4MiB 提到 32MiBxdsServer.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 StatusAccepted / Programmed / ResolvedRefsobservedGeneration、scope
  • GEP-1364:Status and Conditions Update(Programmed 相对 Ready
  • Envoy Gateway v1.9.0 Release Notes:xdsNACKTotalRouteRulesOverlap、TCP/UDP v1 静默跳过、mergeType 仅 xRoute、xDS 默认 32MiB
  • Configuration Issuesgateway.envoyproxy.io/v1.9/troubleshooting/configuration/):Accepted 与 ResolvedRefs 分叉、direct_response 500
  • Gateway Exported Metricsxds_nack_total 等 xDS Server 指标
  • Use egctlegctl x statusegctl x translate --to ir / --to xds
  • System Design / Gateway API Translator Design:XdsIR、InfraIR、status 在翻译中计算
  • tag v1.9.0internal/gatewayapi Translator、internal/ir

站内对照

实验台账

  • 无本环境 Envoy Gateway 集群;不粘贴 egctl / config_dump。官方 Configuration Issues 的 status / 500 示例是文档原样,不是本机复现。

上一篇:运维与升级 · 系列目录 · 下一篇:对照替代路径

相关推荐
ltl1 小时前
Envoy Gateway 南北向全景:附着、IR、xDS 与东西向交界
kubernetes
ltl1 小时前
Tetragon 运行时安全全景:缺口、五轴坐标系与阅读路线
kubernetes
腾讯数据架构师7 小时前
壁仞 GPU 怎么接入 Kubernetes 和 AI 平台?CubeStudio 壁仞算力适配实操
人工智能·容器·kubernetes·cube-studio·ai平台
键盘鼓手苏苏9 小时前
AI 内容生成管线设计:从多模态编排到质量守门的生产级架构
云原生·kubernetes·k8
huaiixinsi10 小时前
Docker 负责打包,Kubernetes 负责调度:一文吃透容器化与 K8s 编排
docker·容器·kubernetes
Kismet_nvi12 小时前
Kubernetes 核心模块详细总结
云原生·容器·kubernetes
三言老师13 小时前
K8s集群运行时异常趋势分析预警实操
java·开发语言·kubernetes
微擎应用市场13 小时前
微擎面板 W7Panel:一站式云原生管理平台,让 Kubernetes 触手可及
云原生·容器·kubernetes
名明鸣冥14 小时前
k8s-agent架构思考(二)
容器·架构·kubernetes