Kubernetes Gateway API 深度实战:从 Ingress 的「表达能力天花板」到生产级流量治理的完全指南(2026)
如果你还在用
kubectl apply -f ingress.yaml管理生产流量,2026 年该认真考虑升级了。Ingress 这个存在了近八年的 API,正被 SIG-NETWORK 用一套更现代、更可移植、角色更清晰的标准逐步取代。本文从工程视角完整拆解 Gateway API:它到底解决了什么痛点、对象模型怎么设计、主流数据面如何落地、如何用 YAML 与 Go 把它跑起来,以及最重要的——如何从 Ingress 平滑迁移。配完整可运行代码。
背景介绍:Ingress 的三道枷锁
2015 年,Kubernetes 社区引入 Ingress 作为「把集群内服务暴露到集群外」的标准方式。十年过去,它依然是最广为使用的入口标准。但只要你做过生产级流量治理,就会撞上三道几乎无法绕开的枷锁。
第一道枷锁:表达能力的天花板。 Ingress 的 spec.rules[].http.paths 只支持「基于 Host + Path 的前缀/精确匹配」。想要做这些事,标准 Ingress 一个都做不到,只能求助厂商注解(annotation):
- 按请求头(Header)路由:
nginx.ingress.kubernetes.io/canary-by-header - 金丝雀按权重切流:
nginx.ingress.kubernetes.io/canary-weight - 请求/响应头改写:
nginx.ingress.kubernetes.io/configuration-snippet - 重写路径、限速、鉴权、超时、重试……全都是厂商私有注解
这意味着:同一份 Ingress YAML,换一个 Controller(从 NGINX 换成 Traefik 或 Emissary)几乎必然失效。你写的不是「Kubernetes 标准」,而是「某个厂商的方言」。
第二道枷锁:可移植性陷阱。 因为能力都塞在注解里,Ingress 事实上不存在跨厂商语义。一份在 NGINX Ingress 上跑得好好的金丝雀配置,搬到 Istio 的 Ingress Gateway 上要整个重写为 VirtualService。团队一旦选型,就被锁死。这在多云、多集群、技术栈演进的场景下是真实的生产负债。
第三道枷锁:角色边界模糊。 Ingress 把「基础设施提供者(谁拥有负载均衡器)、集群运维(流量策略怎么定)、应用开发者(我的服务暴露哪条路径)」三件事揉在一个对象里。开发者想加一条路由,常常要改运维拥有的那份大 YAML,或者反过来。权限、审批、责任边界全部纠缠。
Gateway API 就是 SIG-NETWORK 对这三道枷锁的系统性回答:角色导向(role-oriented)、可移植(portable)、富有表现力(expressive)。它不是 Ingress 的修修补补,而是一次对象模型的重新设计。
一、核心概念:Gateway API 的对象模型
Gateway API 最核心的设计思想是关注点分离:把「入口」拆成三层对象,每层由不同角色拥有。
GatewayClass → 数据面实现的「契约」(基础设施提供者)
Gateway → 一个具体的监听入口(集群运维)
HTTPRoute → 把流量路由到哪个 Service(应用开发者)
1.1 GatewayClass:数据面实现的契约
GatewayClass 定义「用哪套数据面来兑现 Gateway」。它回答的问题是:当我创建一个 Gateway,背后真正干活的是 Istio?Envoy Gateway?还是 Cilium?一个集群里通常有多个 GatewayClass,由平台团队预置好。
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
description: "Envoy Gateway 提供的标准数据面"
注意 controllerName 是个全局唯一字符串,由实现方注册。它的存在本身就解决了可移植性问题:换实现,只改 controllerName 和少量字段,路由语义不变。
1.2 Gateway:一个具体的监听入口
Gateway 由集群运维拥有,描述「在哪个端口、用哪种协议、允许哪些命名空间附加路由」。它对应一个真实的负载均衡器/代理实例。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-gateway
namespace: gateway-system
spec:
gatewayClassName: eg
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- name: example-com-cert
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
expose: "true" # 只有打了这个 label 的命名空间才能挂路由
这里有几个工程上很有价值的点:
listeners[].hostname支持通配符,一个 Gateway 可以接管整个域名的流量。allowedRoutes.namespaces.from: Selector是多租户隔离的关键:运维通过 label 精确控制哪些命名空间的 Route 能挂到这个 Gateway 上,避免任意开发者把脏路由挂到公共入口。tls.mode: Terminate表示 TLS 在 Gateway 处终止;也可设Passthrough把 TLS 透传到后端。
1.3 HTTPRoute:开发者真正关心的东西
HTTPRoute 由应用开发者拥有,描述「满足什么条件的 HTTP 请求,转发到哪个 Service、按什么权重、做什么改写」。它的 spec 结构才是 Gateway API 表现力的核心。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: store-frontend
namespace: store
labels:
expose: "true" # 配合 Gateway 的 Selector 才能挂上
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "shop.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/cart
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Route-Source
value: gateway-api
backendRefs:
- name: cart-service
port: 8080
weight: 100
逐字段拆解:
parentRefs:这条 Route 挂到哪个 Gateway。可以挂多个 Gateway,实现一份路由多处生效。hostnames:该 Route 负责哪些 Host。Gateway 的 listener 有hostname通配,Route 再下钻到具体子域。rules[].matches:匹配条件,支持path(Prefix/Exact/RegularExpression)、headers、queryParams、method。这是 Ingress 做不到的——比如「GET且带x-experiment: blue头的请求走蓝组」。rules[].filters:过滤器。标准内置RequestHeaderModifier、ResponseHeaderModifier、RequestRedirect、URLRewrite、RequestMirror(流量镜像)。backendRefs:后端 Service 列表,带weight。权重切流是标准字段,不再依赖注解。
1.4 GRPCRoute:gRPC 方法级路由
Ingress 对 gRPC 的支持基本等于零(它只能做 TCP 透传)。Gateway API 一等公民般提供了 GRPCRoute,可以按 gRPC 的 service + method 级路由:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: checkout-grpc
namespace: store
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "grpc.example.com"
rules:
- matches:
- method:
service: "checkout.CheckoutService"
method: "CreateOrder" # 只把下单方法路由到 v2
backendRefs:
- name: checkout-v2
port: 9000
- matches:
- method:
service: "checkout.CheckoutService" # 其余方法走 v1
backendRefs:
- name: checkout-v1
port: 9000
这在「gRPC 微服务灰度」场景里价值巨大:你可以只把 CreateOrder 这一个高风险方法灰度到新版本,其余方法保持稳定,而不是整服务切流。
1.5 会话亲和、超时、重试:标准策略字段
Gateway API 还把 Ingress 只能靠注解实现的工程能力变成了标准字段。以 HTTPRoute 为例(部分能力位于 spec.rules[].timeouts 与 backendRefs 的扩展):
# 超时(Gateway API v1.2+ 标准字段)
spec:
rules:
- matches:
- path: { type: PathPrefix, value: /slow }
timeouts:
request: "30s"
backendRequest: "25s"
backendRefs:
- name: slow-service
port: 8080
工程提醒:超时与重试的具体生效方式由数据面实现决定。Gateway API 提供的是语义标准。例如 Envoy Gateway 通过
HTTPRoute的timeouts直接映射到 Envoy 的超时配置;Istio 则可能通过Telemetry或VirtualService风格的Timeout策略。这正是「标准语义、实现解耦」的体现。
1.6 ReferenceGrant:跨命名空间引用的安全闸门
Ingress 时代有个经典隐患:A 命名空间的 Ingress 可以直接引用 B 命名空间的 Service,没有任何显式授权机制,靠 RBAC 粗粒度兜底。Gateway API 引入了 ReferenceGrant——跨命名空间引用必须被显式「授权」:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-store-to-pay
namespace: pay # 被引用方(Service 所在命名空间)
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: store # 引用方(Route 所在命名空间)
to:
- group: ""
kind: Service
没有这份 Grant,store 命名空间的 Route 即便写了 backendRefs: { name: pay-service, namespace: pay },数据面也会拒绝转发。这是一个「默认拒绝(default-deny)」的安全模型,对多团队共享集群极其重要。
1.7 Policy Attachment:可移植的策略扩展机制
Gateway API 不可能把所有策略(限流、鉴权、熔断、WAF)都塞进核心对象,否则又会重蹈 Ingress 注解泛滥的覆辙。它的解法是 Policy Attachment:定义一个独立的 Policy CRD,通过 targetRef 指向 Gateway API 对象来生效。
apiVersion: policy.example.com/v1alpha1
kind: RateLimitPolicy
metadata:
name: api-rl
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: store-frontend
namespace: store
limit:
requestsPerSecond: 100
这套机制的统一价值在于:Policy 与路由解耦,且都能挂到 Gateway / Route / Service 等不同层级。你写的限流策略不会因为换了网关实现就彻底失效(只要新实现也认这个 Policy 的语义)。Istio 的 Telemetry、Cilium 的 CiliumClusterwideNetworkPolicy 都遵循类似思路。
二、架构分析:控制面与数据面的解耦
理解 Gateway API 的架构,关键是抓住一句话:GatewayClass 是「数据面实现契约」,Gateway API 对象只是「意图声明」,真正干活的是背后的数据面控制器。
2.1 一条 HTTPRoute 的旅程
当你 kubectl apply 一份 HTTPRoute,发生了什么?
- 声明落地:etcd 里多了一个
HTTPRoute对象,描述「意图」。 - 实现方 Reconcile:对应的 Gateway 实现(比如 Envoy Gateway 的 controller) watch 到 Gateway/HTTPRoute 变化,开始调和。
- 翻译为数据面配置:controller 把 Gateway API 对象翻译成 Envoy 的
xDS配置(或 Istio 的EnvoyFilter、或 Cilium 的 eBPF 程序)。 - 下发与生效:配置推送到数据面代理,新的路由规则在秒级内生效。
- 状态回写:controller 把「Gateway 的地址、Route 是否被接受、哪个监听器绑上了」写回对象的
status字段。
这带来一个工程红利:你的路由「意图」与「实现」彻底解耦。今天用 Envoy Gateway,明天切到 Cilium,只要两者都实现了 Gateway API 标准语义,你的 HTTPRoute YAML 几乎不用改。
2.2 主流数据面实现横评
| 实现 | 数据面技术 | 特色 | 适用场景 |
|---|---|---|---|
| Envoy Gateway | Envoy(xDS) | 官方参考实现,标准符合度最高 | 想「纯正」用 Gateway API 的团队 |
| Istio | Envoy + Sidecar/Ambient | 服务网格老牌,东西向+南北向统一 | 已用 Istio 做 mesh 的团队 |
| Cilium | eBPF | 内核级转发,性能与可观测性强 | 追求极致性能/已用 Cilium CNI |
| NGINX Gateway Fabric | NGINX | 用户基础和文档最成熟 | 从 NGINX Ingress 平滑迁移 |
| Traefik | Traefik 自有 | 配置动态、易上手 | 中小团队快速落地 |
选型的工程判断:
- 若你从零开始、想要最「标准」的体验:选 Envoy Gateway。它是 SIG-NETWORK 的参考实现,对 Gateway API 新特性跟进最快。
- 若你已在用 Istio 做服务网格:直接用 Istio 的 Gateway API 支持,南北向入口和东西向 mesh 共用一套语义,运维心智统一。
- 若你追求内核级性能、且 CNI 已是 Cilium:用 Cilium Gateway API,转发路径走 eBPF,延迟和开销都更低,还能和服务网格(Cilium mesh / ambient)打通。
- 若你重度依赖 NGINX 的生态和文档:NGINX Gateway Fabric 是低成本迁移路径。
2.3 GAMMA:让 Gateway API 成为服务网格的统一标准
这是 2026 年最值得关注的演进之一。GAMMA(Gateway API for Mesh Management and Administration)的目标,是用同一套 Gateway API 对象,既管「南北向」(外部流量进集群),也管「东西向」(集群内服务间调用)。
传统上,服务网格用完全不同的 CRD:Istio 用 VirtualService/DestinationRule,Linkerd 用 ServiceProfile,Consul 用 ServiceSplitter。这就导致「入口用 Gateway API,mesh 用另一套」的割裂。
GAMMA 的思路是:把 HTTPRoute 的 parentRefs 从「Gateway」换成「一个 Service」(代表「以该 Service 为客户端视角定义流量策略」),从而用同一份 HTTPRoute 表达服务间路由:
# GAMMA 风格:用 HTTPRoute 描述 store 服务调用 pay 服务时的流量切分
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: pay-split
namespace: store
spec:
parentRefs:
- kind: Service
name: store # 以 store 服务为「调用方」视角
group: ""
hostnames:
- "pay.svc.cluster.local"
rules:
- backendRefs:
- name: pay-v1
port: 8080
weight: 90
- name: pay-v2
port: 8080
weight: 10
这意味着:未来你的金丝雀发布、流量切分、头路由,南北向和东西向用同一套 YAML、同一套工具链。这对减少认知负担、统一发布平台价值巨大。截至 2026 年,Istio、Cilium、Linkerd 等都在不同程度上跟进 GAMMA 路线。
2.4 与 Ingress 的架构差异一句话总结
Ingress = 「一个对象 + 一堆厂商注解 + 一个特定 Controller」。
Gateway API = 「多层对象(Class/Gateway/Route)+ 标准字段 + 可插拔数据面 + 显式跨域授权」。
前者把复杂性推给注解和锁定,后者把复杂性前置到清晰的对象边界里。
三、代码实战:从零落地生产级 Gateway
下面用 Envoy Gateway 作为数据面,完整跑通一套生产可用的入口。所有 YAML 均可直接 kubectl apply。
3.1 环境准备:安装 Envoy Gateway
# 1. 添加 Helm 仓库
helm repo add envoy-gateway oci://docker.io/envoyproxy/gateway-helm
helm repo update
# 2. 安装(会自动创建 GatewayClass: envoy-gateway)
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.2.0 \
-n envoy-gateway-system --create-namespace
# 3. 确认 GatewayClass 已就绪
kubectl get gatewayclass
# NAME CONTROLLER ACCEPTED
# envoy-gateway gateway.envoyproxy.io/gatewayclass-controller True
Envoy Gateway 安装后会自动注册一个名为 envoy-gateway 的 GatewayClass,ACCEPTED=True 表示数据面已准备好兑现 Gateway 对象。
3.2 第一个 Gateway 与 HTTPRoute
创建一个对外暴露 HTTPS 的 Gateway,并挂一条路由:
# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-gateway
namespace: gateway-system
spec:
gatewayClassName: envoy-gateway
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- name: example-com-cert # 事先用 cert-manager 或 secret 准备好
---
# route.yaml —— 开发者拥有
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: store-frontend
namespace: store
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "shop.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: store-api
port: 8080
weight: 100
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: store-web
port: 80
weight: 100
应用后查看状态,确认数据面已生效:
kubectl get gateway public-gateway -n gateway-system
# NAME CLASS ADDRESS READY
# public-gateway envoy-gateway 34.120.x.x True
kubectl get httproute store-frontend -n store
# NAME HOSTNAMES AGE READY
# store-frontend ["shop.example.com"] 1m True
READY=True 的前提是:Gateway 拿到了外部地址、且 Route 被监听器接受(包括跨命名空间的 ReferenceGrant 校验通过)。这套 status 机制让「配置到底生效没有」从「猜」变成「可观测」。
3.3 金丝雀发布:标准权重切流
这是 Ingress 时代最痛、最依赖注解的能力,在 Gateway API 里只是 backendRefs 的 weight 字段:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: checkout-canary
namespace: store
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "checkout.example.com"
rules:
- matches:
- path: { type: PathPrefix, value: / }
backendRefs:
- name: checkout-stable # 稳定版,承担 95%
port: 8080
weight: 95
- name: checkout-canary # 金丝雀,先放 5%
port: 8080
weight: 5
渐进式放量可以用一个简单的脚本驱动(思路,非必须):
# 金丝雀从 5% 逐步提到 100%,每步观察监控
for w in 5 20 50 100; do
kubectl patch httproute checkout-canary -n store --type='json' \
-p="[
{'op':'replace','path':'/spec/rules/0/backendRefs/0/weight','value':$((100-w))},
{'op':'replace','path':'/spec/rules/0/backendRefs/1/weight','value':$w}
]"
echo "canary weight -> $w%, 观察 10 分钟"
sleep 600
done
由于 weight 是标准字段,这个「渐进放量」逻辑与具体数据面无关——换 Istio 还是 Cilium,patching 同一份 HTTPRoute 即可。
3.4 头路由与流量镜像:用 Filter 做精细控制
利用标准 filters,可以做到「按请求头分流到调试版本」以及「镜像流量到预发环境做影子验证」:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: search-smart-routing
namespace: search
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "search.example.com"
rules:
# 规则 1:带 x-debug: true 的请求走调试版
- matches:
- path: { type: PathPrefix, value: / }
headers:
- type: Exact
name: x-debug
value: "true"
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Routed-By
value: gateway-api-debug
backendRefs:
- name: search-debug
port: 8080
# 规则 2:正常流量走生产版,并镜像一份到影子服务
- matches:
- path: { type: PathPrefix, value: / }
filters:
- type: RequestMirror
requestMirror:
backendRef:
name: search-shadow
port: 8080
backendRefs:
- name: search-prod
port: 8080
RequestMirror(流量镜像)非常适合「新版本上线前,把真实流量复制一份打过去验证,但不影响真实响应」的灰度验证。注意:镜像请求的响应会被数据面丢弃,只用于观察。
3.5 TLS 终止与跨命名空间引用
跨命名空间的 Route→Service 引用必须配 ReferenceGrant(见 1.6)。完整可运行示例:
# 命名空间 store 的 Route 引用 pay 命名空间的 Service
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: pay-route
namespace: store
spec:
parentRefs:
- name: public-gateway
namespace: gateway-system
hostnames:
- "pay.example.com"
rules:
- matches:
- path: { type: PathPrefix, value: / }
backendRefs:
- name: pay-service
namespace: pay # 跨命名空间!
port: 8080
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-store-to-pay
namespace: pay
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: store
to:
- group: ""
kind: Service
没有 ReferenceGrant,这条跨命名空间路由会被数据面判定为「引用未授权」,流量不会转发。这是 Gateway API 默认安全模型的一部分。
3.6 用 Go 程序读取 Gateway API 资源(真实可运行)
作为平台工程师,你常常需要把「当前集群里所有 Gateway/Route 的状态」纳入自研控制台或巡检脚本。Gateway API 提供了官方 Go 客户端类型,可以像操作原生资源一样操作它们。
go.mod:
module gateway-lister
go 1.22
require (
k8s.io/apimachinery v0.30.0
k8s.io/client-go v0.30.0
sigs.k8s.io/gateway-api v1.1.0
)
main.go:
package main
import (
"context"
"fmt"
"os"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/clientcmd"
gatewayclientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned"
)
func main() {
// 1. 从 kubeconfig 构建配置(生产可用 InClusterConfig)
kubeconfig := os.Getenv("KUBECONFIG")
if kubeconfig == "" {
kubeconfig = os.Getenv("HOME") + "/.kube/config"
}
cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err)
}
// 2. 创建 Gateway API 的 typed clientset
gwClient, err := gatewayclientset.NewForConfig(cfg)
if err != nil {
panic(err)
}
ctx := context.Background()
// 3. 列出所有命名空间下的 Gateway,并打印状态地址
gateways, err := gwClient.GatewayV1().Gateways("").List(ctx, metav1.ListOptions{})
if err != nil {
panic(err)
}
fmt.Println("=== Gateways ===")
for _, g := range gateways.Items {
addrs := []string{}
for _, a := range g.Status.Addresses {
addrs = append(addrs, a.Value)
}
fmt.Printf("- %s/%s class=%s ready=%v addr=%v\n",
g.Namespace, g.Name, g.Spec.GatewayClassName,
gatewayReady(g.Status.Conditions), addrs)
}
// 4. 列出所有 HTTPRoute,并打印每条规则的后端
routes, err := gwClient.GatewayV1().HTTPRoutes("").List(ctx, metav1.ListOptions{})
if err != nil {
panic(err)
}
fmt.Println("=== HTTPRoutes ===")
for _, r := range routes.Items {
fmt.Printf("- %s/%s hostnames=%v\n", r.Namespace, r.Name, r.Spec.Hostnames)
for i, rule := range r.Spec.Rules {
for _, ref := range rule.BackendRefs {
ns := ref.Namespace
if ns == nil {
ns = &r.Namespace
}
fmt.Printf(" rule[%d] -> %s/%s:%d weight=%d\n",
i, *ns, ref.Name, ref.Port, *ref.Weight)
}
}
}
}
func gatewayReady(conds []metav1.Condition) bool {
for _, c := range conds {
if c.Type == "Ready" {
return c.Status == "True"
}
}
return false
}
这段程序的价值在于:它证明了 Gateway API 资源是一等公民的可编程对象。你可以把它接入发布平台,在「放量前自动校验 Route 是否 READY」、在「巡检时发现孤儿 Gateway(没有 Route 挂接)」、在「多集群里聚合所有入口拓扑」——而不必去解析一堆厂商注解。
3.7 可观测性:让入口「看得见」
生产入口不能黑盒。Gateway API 虽然不定义 metrics 格式,但主流实现都会暴露标准信号:
- 指标:Envoy Gateway 暴露 Prometheus 指标(如
envoy_cluster_upstream_rq、envoy_http_downstream_rq_*),可直接接入 Grafana。 - 访问日志:通过 Envoy Gateway 的
EnvoyProxyCRD 开启结构化访问日志(JSON 格式),便于接入 Loki/ELK。 - 状态巡检:上面 3.6 的 Go 程序定期跑,
READY=False的 Route 立刻告警。
一个 Envoy Gateway 开启访问日志的示例:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: envoy-proxy-config
namespace: envoy-gateway-system
spec:
telemetry:
accessLog:
- sinkType: Prometheus
# 或 sinkType: OpenTelemetry 推送到 OTLP collector
四、性能优化与工程权衡
「换网关」最常被问的问题是:性能会不会掉?这里给几个基于架构的判断。
4.1 Gateway API 本身不决定性能,数据面才决定
Gateway API 是「意图声明」,性能取决于底层数据面。Envoy(C++)和 Cilium(eBPF)都是工业级高性能转发引擎,吞吐和延迟与手写 Ingress 配置(底层往往也是 Envoy/Nginx)处于同一量级。换句话说:从 Ingress 迁到 Gateway API,不会因为「标准抽象」而额外损耗性能——瓶颈在 Envoy 配置质量和后端服务。
4.2 xDS 增量推送优于 Ingress 的全量 reload
Envoy Gateway 基于 xDS 协议向 Envoy 推送配置。现代 xDS 支持增量(incremental)推送:你改一条 HTTPRoute,只有受影响的监听器配置被下发,不必像传统 NGINX Ingress 那样 reload 整个 worker。在「路由规则极多、变更频繁」的场景下,这能显著减少配置收敛抖动。
4.3 连接复用与 Keep-Alive
Gateway 的 listeners 层统一配置 TLS 终止和连接复用,代理到后端的 backendRefs 走 keep-alive 连接池(Envoy 默认开启)。相比「每个 Pod 自己终止 TLS、各自建连」的直连架构,Gateway 集中终止 TLS 能大幅下降握手开销。工程上建议:
- 后端 Service 用 HTTP/2(gRPC 必选),让一条连接承载多路复用请求;
- 适当调大 Envoy 的连接池上限,避免突发流量下建连排队;
- 用
timeouts字段给慢接口单独设长超时,避免「一个慢请求拖垮连接池」。
4.4 多租户隔离的代价与收益
Gateway 的 allowedRoutes.namespaces.Selector 让你用「一个共享 Gateway + 多命名空间 Route」的模式,既省负载均衡器成本,又控住权限边界。代价是每个 Route 变更都要经过 ReferenceGrant/Selector 校验,控制台要配套做好自助申请。对中小团队,「每团队一个 Gateway」反而更简单,代价是多几个 LB——这笔账按云账单算即可。
4.5 与 Sidecar 服务网格的取舍
如果你的网格用的是传统 Sidecar 注入(每个 Pod 一个 Envoy 代理),南北向再叠一层 Gateway,转发路径是「客户端 → Gateway Envoy → Sidecar Envoy → 业务容器」,多一跳。2026 年的趋势是 Ambient Mesh(Istio)或 Cilium 无 Sidecar 模式:把代理下沉到节点层(ztunnel / eBPF),Gateway 和 mesh 共用节点级数据面,减少代理跳数。是否上 Ambient,取决于你对「升级复杂度 vs 资源开销」的权衡。
五、迁移路线图:从 Ingress 平滑过渡
别一次性「铲掉」所有 Ingress。推荐双栈并行的渐进迁移。
第一步:装好 Gateway API 实现。 选 Envoy Gateway 或你心仪的数据面,确认 GatewayClass 为 ACCEPTED。
第二步:用 ingress2gateway 自动翻译。 SIG-NETWORK 提供了 ingress2gateway 工具,能把现有 Ingress 转成 Gateway API YAML(注解能力尽量映射为标准字段):
# 把命名空间里所有 Ingress 转成 Gateway API 资源(stdout 预览)
ingress2gateway print --namespace store
# 输出可被 kubectl apply 的 Gateway + HTTPRoute
注意:厂商私有注解(如 NGINX 的 configuration-snippet)往往无法 100% 映射,需要人工补 filters/Policy。翻译结果一定人工 review,不要盲 apply。
第三步:双栈并行,按服务灰度切流。 先把低风险、只读的服务(如文档站、静态前端)切到 Gateway API,观察一周;再把核心 API 切过去;最后保留 Ingress 作为回退通道,直到确认稳定再下线。
第四步:补 ReferenceGrant 与多租户策略。 迁移过程中顺手把跨命名空间引用收口到显式 ReferenceGrant,把「谁能用公共 Gateway」用 namespace Selector 管起来——这本身就是一次安全加固。
第五步:把金丝雀/放量逻辑接到 Gateway API。 用 3.3 的 weight patch 思路替换掉原来依赖注解的发布脚本,让发布平台与数据面解耦。
迁移校验清单:
- 所有对外 Host 在 Gateway 的
listeners[].hostname覆盖范围内 - 每个 Route 的
status均为READY=True - 跨命名空间引用都有对应
ReferenceGrant - TLS 证书引用正确,
mode符合预期(Terminate/Passthrough) - 金丝雀权重、头路由、镜像流量已用
backendRefs/filters表达,无厂商注解残留 - 监控/告警已接入 Gateway 暴露的指标
六、总结与展望
回到开头的问题:2026 年,Ingress 还够用吗?对简单场景依然够用,但对任何需要金丝雀、头路由、gRPC 方法级路由、多租户隔离、跨厂商可移植的团队,Gateway API 已经是更优的默认选择。
回顾本文要点:
- 对象模型分层:
GatewayClass(契约)/Gateway(入口)/Route(路由)三层,把基础设施、运维、开发者的关注点拆干净,这是可移植与多租户的基础。 - 表现力在标准里:权重切流、头路由、gRPC 方法级路由、请求头改写、流量镜像,都是标准字段,不再依赖厂商注解。
- 安全默认拒绝:跨命名空间引用必须显式
ReferenceGrant授权,天然比 Ingress 安全。 - 策略可扩展:
Policy Attachment用targetRef把限流/鉴权/熔断挂到任意 Gateway API 对象,避免注解泛滥。 - GAMMA 统一南北+东西向:同一套
HTTPRoute既能管入口,也能管服务间流量,是服务网格标准化的关键方向。 - 可编程:官方 Go 客户端让入口成为一等可编排对象,方便接入发布平台与巡检。
展望:随着 Gateway API 迭代到 v1.2+,backendTLSPolicy(后端 mTLS)进入标准通道、GRPCRoute 全面 GA、超时/重试等策略字段标准化,它与服务网格、与可观测性体系的咬合会越来越紧。可以预见,未来两三年里,「入口用 Gateway API,mesh 用 GAMMA 风格的同一套对象」会成为云原生流量治理的事实标准,而 Ingress 会像 ReplicationController 一样,慢慢退居兼容层。
给程序员的务实建议:别等。 新项目直接上 Gateway API;老项目用 ingress2gateway 做渐进迁移。你今天写下的每一行 HTTPRoute,都是在为「可移植、可灰度、可审计」的流量基础设施投票。当某天你需要从 NGINX 换到 Cilium、从单云迁到多云时,你会感谢现在没有把业务逻辑锁死在厂商注解里。
本文所有 YAML 与 Go 代码均可在 Kubernetes 1.28+ 与 Envoy Gateway v1.2 / Gateway API v1 标准通道下运行。实际部署请结合你的数据面实现的文档微调 filters 与 Policy 的具体字段。