HTTPRoute YAML 能
apply、Accepted=True,不等于这条规则在吃流量。Gateway
API 允许同一 listener 上挂多条
Route;规范保证每个请求只命中一条规则。更具体的规则赢,并列时更老的
Route 赢。输家可以仍然是 Accepted——直到 Envoy Gateway
v1.9.0 用 RouteRulesOverlap
把「匹配条件完全相同」标成警告。
本文只钉附着与 hostname、matches/filters/backendRefs 如何进入 RDS、GRPCRoute 的差异,以及 v1.9 这条警告的边界。角色模型与金丝雀菜谱见 k8s-network/18(该文钉 Gateway API v1.2 / EG v1.2,字段全集不得搬来当 v1.9)。权重如何变成 Envoy weighted cluster 的 Filter 细节外链 envoy/06,本篇不重写 HCM。
本文是「Envoy Gateway / Gateway API」系列第 6 篇(共 16 篇)。→ 系列目录
篇目 核心内容 第 5 篇 · xDS Translator 与 Infra IR → xDS;推送 ≠ 在服务 第 6 篇 · HTTPRoute / GRPCRoute 匹配与权重 → RDS;阴影与 RouteRulesOverlap 第 7 篇 · TLS / BackendTLSPolicy / SDS 监听器证书与后端 TLS 上一篇:xDS Translator 与 Infra · 下一篇:TLS / SDS
版本锚定:Envoy Gateway v1.9.0;Gateway API v1.6.1 HTTPRoute/GRPCRoute 规范;EG v1.9 路由文档钉
gateway.envoyproxy.io/v1.9/。无伪造 Route status 输出。
一、附着与 hostname
HTTPRoute / GRPCRoute 要进某条 Gateway
listener,必须同时满足:parentRefs 指向该
Gateway(可选 sectionName 或
port)、listener 的 allowedRoutes
允许该 kind 与 namespace、hostname 与 listener hostname
有交集。
EG v1.9 HTTPRoute 页与 Gateway API v1.6.1 一致:
- ParentRefs:通常是
Gateway。
sectionName绑单个 listener;port可一次绑同端口的多个 listener,代价是改 Gateway 端口必须改 Route。 - Hostnames(可选):对 HTTP Host / gRPC
:authority做匹配,先于规则里的 path/header/method。hostname 不允许 IP,也不允许带端口。未写 hostname 时,流量按规则与 filter 走,不再先筛 Host。 - 与 listener 的交集:双方都写了 hostname 时,Route 上不与 listener 相交的名字必须忽略;一个都交不上则不得 Accepted。
v1.9 HTTP routing 任务把不同主机拆成不同
HTTPRoute:example.com、foo.example.com、bar.example.com
各一份。文档写明:hostname 未出现在任何 HTTPRoute
上时,请求不应被路由,客户端看到
404。这是匹配失败,不是
5xx,也不是「控制器没 Accepted」。
v1.9.0 有一条与附着相关的修复,避免把 listener
证书问题误判成 Route
拒绝:HTTPRoute、GRPCRoute、TLSRoute、TCPRoute、UDPRoute 的
Accepted 不再因为「所附着 listener 因缺少 TLS
certificate ref 而未 Programmed」被设为 False。listener 是否
Programmed 与 Route 是否 Accepted
分开计算。排障时不要用「Route 未 Accepted」去解释「HTTPS
listener 没证」。
hostname 与 listener 的交集,规范给了可核对例子:listener
test.example.com 只与写了该名或匹配通配的 Route
相交;*.example.com 匹配
test.example.com 与
foo.test.example.com,不匹配
example.com。Route 上多写的、与 listener
不相交的 hostname 必须忽略;一个都交不上则不得
Accepted。这是附着失败,不是 RDS 阴影。
跨 namespace 的 parentRefs / backendRefs
仍受 ReferenceGrant 约束,机制在第 2 篇。本篇只强调:未
grant 时失败落在 ResolvedRefs,不是 RDS
里多了一条阴影规则。
EG v1.9 HTTP routing 任务还写:hostname 未出现在任何
HTTPRoute 时返回 404。这与「规则默认 / 匹配全部
HTTP」不矛盾——后者只在 hostname 已经选中该 Route(或 Route
未限制 hostname)之后生效。先问 Host,再问 path。
v1.9 另修:ExternalName Service 不得作为
route backend——会生成空地址 cluster,IR 校验失败并卡住整份
snapshot。现在显式 ResolvedRefs: False;集群外
FQDN 应改用 EG Backend。这是整棵 xDS
树的正确性门闩,不是单条 404。
二、matches / filters / backendRefs
规则内部三件套对应 IR 再对应 RDS
里的一条(或一组)route。EG v1.9 HTTPRoute 文档对 matches
的例子与规范相同:一条 rule 里两个 match
是「/foo 前缀且 header
version=2」或「/v2/foo
前缀」——满足任一即可。不要把「同一 rule 多个
match」理解成必须同时成立。
| 字段 | 规范要点(Gateway API v1.6.1) | 落到数据面时 |
|---|---|---|
matches |
同一 rule 下多个 match 是 或;一个
match 内 path/header/query/method 是
与。未写 matches 时 HTTPRoute 默认为
/ 的 PathPrefix,匹配全部 HTTP。Path 类型包括
Exact / PathPrefix / RegularExpression(以后两者是否 Core
以实现与 channel 为准,不在此把未核字段写成 v1.9 全集) |
进入 RDS 的 match 树;Envoy 按顺序取第一条命中 |
filters |
Core 必须实现(HTTPRouteRule 上
RequestHeaderModifier、RequestRedirect 为 Core)。URLRewrite
与 RequestRedirect 不得组合。不兼容时
Accepted=False,reason 可用
IncompatibleFilters。多次指定同一 core filter
的语义在规范里是 unspecified / implementation-specific |
多数变成 HCM per-route 或 filter 配置;EG 扩展走
extensionRef |
backendRefs |
未指定且没有会直接响应的 filter 时,HTTPRoute 规范要求返回 500 | 每个 backendRef 对应 Envoy cluster(或 v1.9 experimental
mergeBackends 下的共享 cluster,第 10 篇) |
weight |
同 rule 多 backend 按权重分流 | RDS weighted clusters,不是第二条 HTTPRoute |
v1.9 HTTP routing 任务用 header env: canary
做更具体匹配:有 header 走 canary Service,否则走稳定
Service。这是同一 HTTPRoute
内的规则优先级(更具体者优先),不是两条 Route 抢
listener。站内 18 的金丝雀实验基于 EG
v1.2,不得把那次命令输出写成 v1.9 事实。
Gateway API 对跨 Route 的优先级写在
HTTPRouteRule / Listener allowedRoutes
叙述里,并列时继续比:
- 该 Route 类型定义的最具体匹配(HTTP:非通配 hostname 字符数、hostname、path、header 等,以 v1.6.1 spec 原文为准)。
- 更老的 Route(
creationTimestamp)。 {namespace}/{name}字典序更前。- 仍并列则该 Route 内部第一条满足条件的 rule。
Envoy 侧是「RDS 列表从上到下,第一条匹配获胜」。EG
翻译必须把上述优先级变成这个列表顺序。社区 issue #9135
上维护者说明:两条合法 HTTPRoute 可以都是
Accepted=True /
ResolvedRefs=True,较老且匹配相同的那条吃流量,较新的被
Envoy 顺序阴影。这是规范行为,不是控制器「没挂上」。
v1.9 任务还展示两类 EG 扩展,不要当成 Gateway API core:
- JWT claim → header 后再匹配:
SecurityPolicy的recomputeRoute,且必须有 fallback rule;策略要同时挂 fallback 与带 claim header 的 rule,避免伪造 header。 - Cookie 匹配:
HTTPRouteFilter+ HTTPRouteextensionRef。
超时:timeouts.request /
backendRequest 自 Gateway API v1.2 起在
Standard channel。backendRequest 不得大于
request。v1.9.0 修过:由
backendRequest 推导的 per-retry timeout 在未配
retry backoff 时也会被应用。
flowchart TD
req["Request Host and path"] --> host{"Hostname match"}
host -->|"no HTTPRoute hostname"| miss["404"]
host -->|"match route A and B"| spec{"Gateway API specificity"}
spec -->|"A more specific"| a["RDS first: route A"]
spec -->|"tie"| ts{"Older creationTimestamp"}
ts --> a
ts -->|"same timestamp"| name{"namespace/name lexical"}
name --> a
a --> envoy["Envoy first-match wins"]
shadow["Route B Accepted still True"] -.-> envoy
图:同 listener 上多条 HTTPRoute 的匹配顺序。阴影 Route
可以保持 Accepted;v1.9 对完全相同的 match
另打 RouteRulesOverlap(第四节)。
三、GRPCRoute 差异
GRPCRoute 自 Gateway API v1.1.0 起在
Standard channel,apiVersion 为
gateway.networking.k8s.io/v1。EG v1.9 GRPC
routing 任务用 grpcurl 走
yages.Echo/Ping,并说明支持 gRPC-Web。
与 HTTPRoute 的机制差,而不是口味差:
| 维度 | HTTPRoute | GRPCRoute |
|---|---|---|
| 默认匹配 | 未写 matches → PathPrefix / |
未写 matches → 匹配全部 gRPC 请求 |
| 方法匹配 | URI path,例如 /package.Service/Method |
service + method 字段;EG
文档支持 Exact(默认)与
RegularExpression |
| 无 backend 且无直接响应 filter | HTTP 500 | gRPC UNIMPLEMENTED |
| 过滤器 | HTTPRoute filters | 功能相同的头修改等复用 HTTPRoute filter 形状;v1.9 允许
GRPCRoute rule 经 extensionRef 引用 EG
HTTPRouteFilter(rewrite、direct
response、credential、cookie match) |
| 超时 | HTTPRoute timeouts |
长流常用 BackendTrafficPolicy 把 HTTP
request timeout 设为 0s(v1.9 任务页) |
何时必须 HTTPRoute:要在同一 hostname 上用 URI 区分普通 HTTP 与 gRPC。规范建议分主机;若实现强制两类 Route 的 hostname 唯一,混服只能两边都用 HTTPRoute。
EG v1.9 允许 GRPCRoute 经 extensionRef 引用
HTTPRouteFilter,从而在 gRPC 规则上做 URL
rewrite(authority/host 与 regex
:path)、direct response、credential injection
与 cookie 匹配。这是 v1.9 New features,不是 Gateway API
core。不要把这些能力写成「GRPCRoute spec 自带」。
跨 Route 合并:GRPCRoute spec 写明 不得与 HTTPRoute 做 merging;优先级在 GRPC 自己的 hostname / service / method / header 尺度上计算,并列时同样是时间戳再名字。
Gateway API v1.6.0
发行说明改过语气:以前规范要求实现拒绝同一 hostname 上的
HTTPRoute 与 GRPCRoute(不少实现并未做到);现在
可以拒绝,也
可以让二者并存(#4598)。EG v1.9 GRPCRoute
页仍写「实现可以强制唯一」。本文不把「EG
一定拒绝」写成 v1.9 保证——以集群里实际 Accepted
条件为准,本篇未跑。
四、v1.9 RouteRulesOverlap
v1.9.0 Release Notes 原文:新增
RouteRulesOverlap warning
status condition,用于「某条 route 的 match
条件与同一 listener 上另一条 route
完全相同」,以便发现被静默阴影的规则。
边界必须写死:
- 它针对 identical match,不是「一个 prefix 盖住另一个更具体 path」。更具体者获胜是 Gateway API 的正常优先级,不应被当成故障。
- 它是 warning condition,不是把
Accepted打成 False。issue #9135 的维护者说明与规范一致:重叠本身可以合法(宽 fallback + 窄规则)。 - 因此:
Accepted=True且无 Overlap,仍可能因「较宽规则排在较新 Route 前面」而看不到流量——只要匹配不是逐字段相同。Overlap 解决的是「复制了一条一模一样的 HTTPRoute、只改了 backend」这种值班盲区。
发现 Overlap 之后的处理是改匹配(hostname / path / header
/ method /
query)或删掉被阴影的那条,而不是重装控制器。金丝雀应落在同一
rule 的 weighted backendRefs
或更具体的 header match,不要复制整份
HTTPRoute 抢同一组 match。
排障时把「没流量」拆开:hostname 未命中是 404;backend 未指定且无直接响应 filter 是 500;ExternalName 是 ResolvedRefs False 且可能卡住整份 snapshot;完全相同 match 才是 Overlap 警告。四者都可能伴随 Accepted=True 的某一条 Route,不能用单一绿灯否定其它失败。
v1.9
没有把这条条件承诺为「所有部分重叠都会报警」。部分重叠、跨
GRPC/HTTP 的 hostname 策略、以及实验性 rule
name 字段,都不在本篇展开。
五、谱系、争论与开放问题
谱系
Ingress:host + path + 不可移植 annotation
→ Gateway API HTTPRoute(角色分离、可移植 core、显式优先级)
→ GRPCRoute(封装协议单独成资源,避免生态分裂)
→ 实现把优先级编译成 Envoy RDS 有序列表
→ EG v1.9:用 RouteRulesOverlap 补「Accepted 仍被阴影」的可观测缺口
HTTP 反向代理「第一条匹配获胜」是数据面常识;Gateway API 要在多租户、多对象上给出可移植的排序键(具体度、时间戳、名字),否则换实现金丝雀会翻面。EG 的工作是遵守这组键,并在完全重复时发出警告。
争论:重叠算错误还是警告
A 侧(早期 issue #8101 的诉求):相同 exact path 两条 Route 都 Accepted,结果不确定,status 应标冲突。
B 侧(规范 + v1.9 实现):重叠常是故意的 fallback;拒绝会误伤。最终选择是 warning + 保持 Accepted,只覆盖 identical match。
这是「status 能否当生效 SLO」的一个实例:警告存在,流量仍可能全在另一条规则上。
开放问题
- Overlap 是否应覆盖「语义覆盖」而不只是字段全等(例如
/prefix 阴影/api)?覆盖会带来大量故意 fallback 的噪音。 - HTTPRoute 与 GRPCRoute 同 hostname 的可选拒绝,在 EG 的实际默认是什么?v1.6 规范已放松;需要实现级测试,本文不测不写。
- 多 Route 权重金丝雀与单 Route weighted backends 在排障上的成本差:前者制造阴影,后者把分流留在一条 RDS 规则内。
六、小结
- Hostname 先于规则;未匹配主机在 EG 任务文档里是 404,不是 500。
- matches 的或/与、filters 兼容性、backendRefs 与 weight 决定 RDS 条目;跨 Route 优先级由 Gateway API 规定,Envoy 用有序列表执行。
- GRPCRoute 用 service/method 匹配;无后端时是 UNIMPLEMENTED;与 HTTPRoute 不得按规范合并。
- v1.9
RouteRulesOverlap只警告同 listener 上 完全相同 的 match;Accepted 绿仍可能被更老或更具体的规则阴影。
下一篇把「谁在终止
TLS」从路由里拆出来:监听器证书、BackendTLSPolicy、以及 v1.9
SDS 的 unix:// 与共享
system_ca_certificates。
七、参考资料
规范 / 官方文档(A)
- Gateway API v1.6.1 HTTPRoute / GRPCRoute spec(matches 或与、优先级、无 backend 的 500 / UNIMPLEMENTED、Merging)。
- Gateway API v1.6.0 发行说明:同 hostname 上 HTTPRoute 与 GRPCRoute 由 MUST-reject 改为可选(#4598)。
- Envoy Gateway v1.9:HTTPRoute、GRPCRoute、HTTP Routing、GRPC Routing。
- Envoy Gateway v1.9.0 Release
Notes:
RouteRulesOverlap;Accepted与 listener Programmed 分离;ExternalNamebackend 拒绝。
源码 / 追踪(A/B)
核心论文 / GEP
- Gateway API HTTPRoute 匹配优先级(规范正文)——多对象下「一条请求一条规则」的可移植定义。
- GRPCRoute 纳入标准的理由见 EG v1.9 GRPCRoute 页 Background(封装协议、避免生态分裂);GEP 编号不在本篇展开。
实验 / 工具
- 实验台账:未跑。不粘贴伪造
kubectl get httproutestatus,不引用 k8s-network/18 的 v1.2 金丝雀输出作为 v1.9 结果。
站内对照
→ 上一篇:xDS Translator 与 Infra · 系列目录 · 下一篇:TLS / BackendTLSPolicy / SDS
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Envoy Gateway】南北向全景:缺口、五轴坐标系与 16 篇路线
相对 Gateway API 产品教程、Cilium 南北向边界、Envoy 消费侧与 istiod 翻译,钉清 Envoy Gateway v1.9.0 控制面内核缺口;定义附着/status、IR、xDS、Envoy 数据面、入口之后东西向五条轴,给出 16 篇阅读路线。
【Envoy Gateway】排障坐标系:未 Accepted、空 IR、xDS NACK 与旧快照
按五轴映射 Envoy Gateway v1.9.0 南北向故障:status 未绿、Translator 产出空或错误 XdsIR、xDS NACK、Envoy 仍服务旧快照、入口之后的东西向 CNI;口诀是先点名轴,再下钻模块。
Envoy Gateway / Gateway API:从 CR 附着到 xDS
补齐站内 Gateway API 产品教程与 Envoy 数据面消费侧之上的南北向控制面内核:附着与 status、Provider watch、IR 翻译、xDS 与 Infra、路由/TLS/L4/Policy 边界,并以排障与相对 Cilium Gateway / Istio / Ingress 的选型收束。
【Envoy Gateway】角色与附着:GatewayClass / Gateway / Route 各保证什么
钉清 Gateway API v1.6.1 角色分离在 Envoy Gateway v1.9.0 里的失败语义:parentRefs 与跨 namespace、ReferenceGrant 握手、Accepted 相对 Programmed / ResolvedRefs,以及 YAML 已 apply 仍无流量时该先查哪条条件。