告别 Ingress Nginx:Kubernetes Gateway API 生产级迁移实战——三层模型、流量分割与跨命名空间路由全解析
2025 年 11 月,Kubernetes 社区正式宣布最主流的 Ingress 控制器 Ingress Nginx 将于 2026 年 3 月停止维护。这不是某家厂商的弃坑,而是 SIG-Network 对全社区的一声提醒:陪伴我们近十年的 Ingress API,已经到了该"退休"的节点。继任者不是另一个 annotation 满天飞的控制器,而是从设计层面重写流量治理模型的 Gateway API。
本文从 Ingress 的真实痛点出发,逐层拆解 Gateway API 的三层资源模型与三种角色边界,结合 Envoy Gateway 给出从安装、Ingress 迁移、金丝雀流量分割、gRPC 路由、跨命名空间引用到 TLS 终止的完整生产实战,并用 client-go 演示如何以代码方式编排 HTTPRoute。最后聊聊实现选型、可观测性与 GAMMA 带来的"网关即服务网格"未来。
一、背景介绍:Ingress 为什么不够用了
如果你在 2017 年就开始玩 K8s,一定对下面这份清单无比熟悉:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Served-By: $hostname";
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
它能用,但"能用"和"好用"之间隔着三道难以逾越的裂缝。
1.1 表达能力的天花板:高级路由只能靠 annotation
Ingress 规范本身只定义了两件事:基于 host + path 的路由。只要你想做下面任何一件"稍微高级点"的事,就必须向具体控制器的私有 annotation 低头:
- 按请求头(Header)或 Query 参数路由?→ 私有 annotation
- 按 HTTP 方法(GET/POST)分流?→ 私有 annotation
- 流量按比例切分做金丝雀?→ 私有 annotation(
canary-weight) - 请求镜像(shadow/mirror)到预发环境?→ 私有 annotation
- 重写路径、改响应头、做重定向?→ 私有 annotation
问题在哪?nginx.ingress.kubernetes.io/* 这套注解只有 Ingress Nginx 认;你换成 Traefik、换成 Emissary、换成云厂商的 ALB Ingress,这套注解全部失效。结果就是:Ingress 资源在纸面上是"标准",落到生产里却是"各家自说自话"。一份 Ingress YAML 离开了它诞生的集群,几乎无法平移。
1.2 角色边界的缺失:管理员和应用开发者抢同一个资源
真实企业里,流量入口的权责天然是分层的:
- 平台管理员(Infra Provider) 决定"用哪个网关实现、跑在哪个基础设施上、TLS 证书怎么签发";
- 集群运维(Cluster Operator) 负责"网关实例怎么部署、监听哪些端口、对外暴露方式";
- 应用开发者(App Developer) 只关心"我的
/api路由到我的api-svc:8080"。
但 Ingress 把所有这些都塞进一个资源里。开发者想加一条路由,就得碰一个可能被管理员加过全局规则的同一个 Ingress;管理员想改 TLS,又可能动到开发者的路由。权责边界模糊,在大型组织里是事故温床。
1.3 协议视角的狭隘:gRPC、TCP、UDP 都是二等公民
Ingress 本质是 HTTP/HTTPS 的规范。你想做 gRPC 的按 method 路由?想做 TCP/UDP 的游戏或数据库流量入口?要么走 hack(把 gRPC 当 HTTP/2 硬塞),要么另起一套 LoadBalancer Service 或自定义 CRD。流量治理的标准,被人为砍掉了一大半。
Gateway API 就是为这三道裂缝而生的。 它由 SIG-Network 主导,2023 年底 GA(v1.0),如今 v1.1/v1.2 已稳定覆盖 HTTP、gRPC、TCP、UDP、TLS 路由,并被 Envoy Gateway、Cilium、Istio、NGINX Gateway Fabric 等主流实现全面支持。
二、核心概念:把"网关"拆成三层资源与三种角色
Gateway API 最革命性的设计,是把"一个 Ingress 资源"按职责拆成多个带角色边界的资源。理解这三层,就理解了整个 Gateway API。
2.1 三种角色(Role)
| 角色 | 对应资源 | 关心什么 | 通常不关心 |
|---|---|---|---|
| 基础设施提供者 Infra Provider | GatewayClass | 网关的"品牌/实现"(Envoy?Cilium?云厂商?) | 具体路由规则 |
| 集群运维 Cluster Operator | Gateway | 网关实例长啥样、监听哪些端口、怎么对外暴露 | 某个业务的具体 path |
| 应用开发者 App Developer | HTTPRoute / GRPCRoute / TCPRoute 等 | 我的流量怎么路由到我服务 | 网关跑在哪个节点 |
2.2 三层资源模型
GatewayClass ──(实现类型)──► Gateway ──(监听+绑定)──► HTTPRoute/GRPCRoute
(平台管理员) (集群运维) (应用开发者)
│ │ │
Envoy / Cilium listeners: parentRef:
/云厂商 - port 443 gateway: prod-gw
- protocol HTTPS host: example.com
- TLS: cert-manager rules: 路由到我的 svc
GatewayClass:描述"网关的实现种类",类似 StorageClass 之于存储。它定义一个controllerName(比如gateway.envoyproxy.io/gatewayclass-controller),告诉集群"这种网关由谁来实现"。Gateway:一个具体的网关实例。它声明监听什么端口、什么协议、怎么处理 TLS,以及(可选)如何被外部流量访问(addresses/infrastructure)。一个 Gateway 可以绑定多个 Route。xRoute:具体的路由规则。最常用的是HTTPRoute;此外还有GRPCRoute、TCPRoute、UDPRoute、TLSRoute。每个 Route 通过parentRef挂到某个 Gateway 上。
这套模型的妙处:开发者只在自己的命名空间里写 HTTPRoute,完全不需要碰 Gateway 的 TLS 配置;运维改 Gateway 的监听端口,也不会破坏开发者的路由。权责第一次在 API 层面被干净地切开。
2.3 Route 的规则结构:matches + filters + backendRefs
一条 HTTPRoute 的 rules 由三块组成,这是 Gateway API 表达力的核心:
rules:
- matches: # 匹配条件(比 Ingress 丰富得多)
- path:
type: PathPrefix
value: /api
headers: # ✅ Ingress 做不到:按请求头匹配
- type: Exact
name: X-Canary
value: "true"
method: POST # ✅ Ingress 做不到:按方法匹配
filters: # 流量修饰(重写/重定向/改头/镜像)
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs: # 后端,支持多后端 + 权重(金丝雀)
- name: api-svc
port: 8080
weight: 90
- name: api-canary-svc
port: 8080
weight: 10
matches 支持 host、path、header、query、method 的组合;filters 支持 RequestHeaderModifier、RequestRedirect、URLRewrite、RequestMirror(流量镜像);backendRefs 支持多后端带权重——这就是金丝雀发布的原生能力,不再需要 annotation。
三、架构分析:一个请求如何穿过 Gateway API
理解控制面与数据面的协作,才能在生产里排障。以 Envoy Gateway 为例(当前社区采用率最高的开源实现之一):
┌─────────────────────────────────────────────┐
客户端 ───────► │ Envoy Proxy (数据面, 由 Gateway 推导部署) │
(HTTPS:443) │ - 监听 443,终止 TLS │
│ - 按 HTTPRoute 规则做 L7 路由 │
│ - 权重分流 / 头匹配 / 重写 │
└───────────────┬───────────────┬─────────────┘
│ │
┌─────────▼───┐ ┌──────▼────────┐
│ api-svc:8080│ │api-canary:8080│
└─────────────┘ └───────────────┘
┌──────────────────────────────────────────────────────────┐
│ Envoy Gateway Controller (控制面) │
│ watch GatewayClass/Gateway/HTTPRoute/GRPCRoute │
│ → 翻译成 Envoy xDS 配置 → 推送给上面的 Envoy Proxy │
└──────────────────────────────────────────────────────────┘
关键点:
- Gateway/Route 只是"意图(intent)",真正的流量处理发生在独立的 Envoy 代理(数据面)。控制器(控制面)负责把你的声明式资源翻译成 Envoy 能理解的 xDS 配置并下发。
- Gateway 决定数据面怎么部署:Envoy Gateway 默认会为 Gateway 自动创建一个 Deployment + Service(LoadBalancer 或 NodePort,取决于
infrastructure配置),你不用手写 Envoy 配置。 - 实现可替换:你今天用 Envoy Gateway,明天想换成 Cilium(基于 eBPF,无 sidecar),只要换
GatewayClass的controllerName,上层 HTTPRoute 几乎不用改——这正是标准化带来的红利。
3.1 多实现生态与一致性测试(Conformance)
Gateway API 有一套跨实现的一致性测试(Conformance Profiles)。每个实现会声明自己通过了哪些 Profile(比如 GatewayHTTPConformance、GRPCRouteConformance)。这意味着:一份通过 conformance 的 HTTPRoute,在 Envoy Gateway、Cilium、Istio 上行为应当一致。这是 Ingress 时代完全不存在的保证。
主流实现取向(2026 现状):
| 实现 | 数据面技术 | 适合场景 |
|---|---|---|
| Envoy Gateway | Envoy(xDS) | 通用、功能最全、社区最活跃 |
| NGINX Gateway Fabric | NGINX | 想沿用 NGINX 心智模型的团队 |
| Cilium Gateway API | eBPF + Envoy | 已有 Cilium CNI,追求内核级性能 |
| Istio (GAMMA) | Envoy(sidecar/ambient) | 已用 Istio 做服务网格,网关网格统一 |
四、代码实战:从零到生产
下面以 Envoy Gateway 为例,给出一条可复制的迁移路径。所有命令在 K8s ≥ 1.25 集群验证(2026 年主流为 1.30+)。
4.1 安装 Envoy Gateway 与标准 CRD
# 1. 安装 Gateway API 核心 CRD(各实现共享)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
# 2. 安装 Envoy Gateway(含其扩展 CRD + 控制器)
helm repo add envoy-gateway https://envoy-gateway.github.io/helm-charts
helm repo update
helm install eg envoy-gateway/gateway-envoy \
-n envoy-gateway --create-namespace \
--version v1.3.0
# 3. 确认控制器就绪
kubectl get pods -n envoy-gateway
# NAME READY STATUS RESTARTS
# envoy-gateway-<hash> 1/1 Running 0
安装完成后,Envoy Gateway 会自动注册一个名为 eg 的 GatewayClass:
kubectl get gatewayclass
# NAME CONTROLLER ACCEPTED AGE
# eg gateway.envoyproxy.io/gatewayclass-controller True 2m
4.2 第一步:把最朴素的 Ingress 迁成 Gateway + HTTPRoute
先在 infra 命名空间由运维创建网关实例:
# gateway.yaml —— 集群运维的职责
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gw
namespace: infra
spec:
gatewayClassName: eg
listeners:
- name: https
port: 443
protocol: HTTPS
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- name: example-com-cert # 由 cert-manager 签发
allowedRoutes:
namespaces:
from: All # 允许所有命名空间的 Route 挂上来
开发者在自己的业务命名空间写 HTTPRoute,通过 parentRef 指向它:
# httproute-api.yaml —— 应用开发者的职责
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: shop # 业务命名空间,和 Gateway 不同
spec:
parentRefs:
- name: prod-gw
namespace: infra
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-svc
port: 8080
注意两个反直觉但重要的点:
- HTTPRoute 可以在自己的命名空间,而 Gateway 在另一个命名空间。这是 Ingress 做不到的。靠
parentRefs[].namespace指定即可,但需要在 Gateway 的allowedRoutes.namespaces.from: All(或Selector)授权。 - host 在 Gateway 的 listener 上做"准入"(
hostname: "*.example.com"),HTTPRoute 上再声明具体 host。双层校验避免开发者抢注不属于自己的域名。
4.3 进阶:按请求头做金丝雀 + 流量镜像
真实灰度场景:给带 X-Canary: true 的请求头打到 canary,其余走稳定版;同时把 100% 流量镜像到预发做回归验证。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-canary
namespace: shop
spec:
parentRefs:
- name: prod-gw
namespace: infra
hostnames: ["api.example.com"]
rules:
# 规则一:带 canary 头的请求,全量进 canary
- matches:
- path:
type: PathPrefix
value: /api
headers:
- type: Exact
name: X-Canary
value: "true"
backendRefs:
- name: api-canary-svc
port: 8080
weight: 100
# 规则二:其余流量,稳定:canary = 95:5 按比例
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-svc
port: 8080
weight: 95
- name: api-canary-svc
port: 8080
weight: 5
filters:
# 流量镜像:复制一份到预发,但不影响主链路响应
- type: RequestMirror
requestMirror:
backendRef:
name: api-staging-svc
port: 8080
这里 weight 总和不要求 100(实现会按比例归一化),但建议写满 100 便于阅读。RequestMirror 是 Ingress 时代要写一长串 configuration-snippet 才能勉强实现的能力,现在是一等公民。
4.4 gRPC 路由:按 method 精确分发
gRPC 是 HTTP/2 上的 POST,但 Gateway API 提供了专门的 GRPCRoute,可以按 service + method 路由——对微服务拆分极其友好:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: order-grpc
namespace: shop
spec:
parentRefs:
- name: prod-gw
namespace: infra
hostnames: ["grpc.example.com"]
rules:
# 把 Order 服务的查询类方法路由到只读副本
- matches:
- method:
service: "order.OrderService"
method: "GetOrder" # 只匹配 GetOrder
backendRefs:
- name: order-readonly-svc
port: 9000
# 写操作走主库
- matches:
- method:
service: "order.OrderService"
method: "*" # 其余全部方法
backendRefs:
- name: order-primary-svc
port: 9000
method 字段直接吃 package.Service/Method 的 gRPC 全限定名,这是 Ingress(它只认 path)无论如何也表达不了的。
4.5 跨命名空间引用:ReferenceGrant 的安全闸门
前面让 shop 命名空间的 Route 引用 infra 命名空间的 Gateway,这是正向引用,由 Gateway 的 allowedRoutes 控制。但如果你想让 Route 反向引用另一个命名空间的后端服务(比如 shop 的 Route 把流量发给 payments 命名空间的 pay-svc),需要显式的 ReferenceGrant——这是 Gateway API 的安全设计:跨命名空间引用必须双向授权。
# 在 payments 命名空间声明:允许 shop 命名空间引用我的 pay-svc
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-shop-to-pay
namespace: payments
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: shop
to:
- group: ""
kind: Service
name: pay-svc
没有这份 Grant,即使 HTTPRoute 写了 backendRefs: pay-svc,控制器也会拒绝生效。这把"跨命名空间流量逃逸"从运维约定升级成了API 级别的强制约束。
4.6 TLS 终止:与 cert-manager 无缝衔接
Gateway 的 listener 直接消费 Secret,配合 cert-manager 自动续期:
# cert-manager 自动签发并写入 example-com-cert Secret
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: infra
spec:
secretName: example-com-cert
dnsNames: ["*.example.com"]
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
Gateway listener 的 certificateRefs 指向这个 Secret 即可。cert-manager 续期时只更新 Secret,Envoy Gateway 通过 informer watch 到变更后热加载,无需重启代理。
4.7 一键迁移工具:ingress2gateway
社区提供了官方迁移工具,能读取集群里现存的 Ingress(含 Ingress Nginx 的 annotation),自动翻译成 Gateway API 资源:
# 安装
go install github.com/kubernetes-sigs/ingress2gateway@latest
# 预览:把当前集群所有 ingress-nginx 资源转成 Gateway API YAML(不真改集群)
ingress2gateway print --providers=ingress-nginx
# 输出示例(节选)
# ---
# apiVersion: gateway.networking.k8s.io/v1
# kind: Gateway
# metadata: { name: ingress-nginx, namespace: ingress-nginx }
# spec:
# gatewayClassName: eg
# listeners:
# - name: https-443
# port: 443
# protocol: HTTPS
# tls: { ... }
# ---
# apiVersion: gateway.networking.k8s.io/v1
# kind: HTTPRoute
# ...
工具会尽量把常见 annotation 映射成标准 filter(canary-weight → backendRefs.weight、rewrite-target → URLRewrite 等)。但务必人工复核:私有 snippet 类 annotation 无法自动翻译,需要你手动补成 ExtensionRef 或后端策略。
4.8 用代码编排 HTTPRoute:client-go 实战
当路由规则要由平台自身的控制面动态生成(比如多租户 SaaS 按租户自动下发路由),用 YAML 手工维护就不现实了。Gateway API 提供了官方 Go client,可以这样程序化创建 HTTPRoute:
package main
import (
"context"
"fmt"
"log"
gatewayv1 "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/typed/apis/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gw "sigs.k8s.io/gateway-api/apis/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 1. 构建客户端(生产用 in-cluster config,本地用 kubeconfig)
cfg, _ := rest.InClusterConfig()
// cfg, _ := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig")
client, err := gatewayv1.NewForConfig(cfg)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
tenant := "acme"
// 2. 构造一个按租户子域名路由的 HTTPRoute
route := &gw.HTTPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: tenant + "-route",
Namespace: "shop",
Labels: map[string]string{"tenant": tenant},
},
Spec: gw.HTTPRouteSpec{
CommonRouteSpec: gw.CommonRouteSpec{
ParentRefs: []gw.ParentReference{{
Name: "prod-gw",
// Namespace 必须显式给,因为 Gateway 在 infra 命名空间
Namespace: ptr("infra"),
}},
},
Hostnames: []gw.Hostname{gw.Hostname(tenant + ".example.com")},
Rules: []gw.HTTPRouteRule{{
Matches: []gw.HTTPRouteMatch{{
Path: &gw.HTTPPathMatch{
Type: ptr(gw.PathPrefix),
Value: ptr("/"),
},
}},
BackendRefs: []gw.HTTPBackendRef{{
BackendRef: gw.BackendRef{
BackendObjectReference: gw.BackendObjectReference{
Name: gw.ObjectName(tenant + "-svc"),
Port: ptr(gw.PortNumber(8080)),
},
Weight: ptr(int32(100)),
},
}},
}},
},
}
// 3. 创建(已存在则 Update,体现"声明式幂等")
_, err = client.HTTPRoutes("shop").Create(ctx, route, metav1.CreateOptions{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("tenant %s route created\n", tenant)
}
func ptr[T any](v T) *T { return &v }
这段代码的工程价值在于:路由即代码(Route as Code)。配合 controller-runtime 你可以写自己的 Operator,监听业务 CRD 变化自动维护 HTTPRoute,把流量治理真正纳入 GitOps 与平台工程体系。
五、性能优化与生产级建议
Gateway API 本身不处理流量,性能取决于你选的实现。几个关键调优点:
5.1 按场景选型,别盲目追新
- 追求功能最全、生态最成熟 → Envoy Gateway。它的 xDS 数据面在 L7 路由、可观测性上打磨最久。
- 集群已经跑 Cilium CNI,且要极致延迟 → Cilium Gateway API(eBPF 绕过 kube-proxy,连接建立延迟更低,适合高频短连接)。
- 已经用 Istio 做服务网格 → 直接用 GAMMA 模式,让 Gateway 和网格共用一套控制面,避免"两套代理两套心智"。
5.2 连接复用与超时:用 BackendTrafficPolicy 兜底
网关层最容易被忽略的坑是后端连接池耗尽和无限等待。Envoy Gateway 提供 BackendTrafficPolicy(扩展资源)精细控制:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: api-timeout
namespace: shop
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
timeout:
http:
requestTimeout: 5s # 单请求最多 5s
connectionIdleTimeout: 60s
connection:
bufferLimit: 256KiB
maxRequestsPerConnection: 100
5.3 可观测性:指标原生可拿
Envoy 数据面天然暴露 Prometheus 指标(envoy_cluster_upstream_rq、envoy_http_*)。Envoy Gateway 默认在 :19001/metrics 暴露,接一个 ServiceMonitor 就能进 Grafana:
# 关键看板指标
# - envoy_cluster_upstream_rq_time → 后端 P99 延迟
# - envoy_cluster_upstream_rq_503 → 后端错误率(金丝雀回滚信号)
# - envoy_listener_http_downstream_rq_2xx/5xx → 网关入口状态分布
金丝雀发布请务必基于这些指标做自动回滚(配合 Flagger 或 Argo Rollouts 的 Gateway API provider),而不是人工盯屏。
5.4 避免"Gateway 单点":横向扩展与优雅下线
Envoy Gateway 的 Envoy 代理是无状态 Deployment,直接 kubectl scale 或 HPA 即可横向扩容。下线时记得配 terminationGracePeriodSeconds + preStop 钩子排空连接,否则滚动更新会掐掉在途请求。
六、总结与展望:Gateway API 之后是什么
回看这一路:Ingress 用极简的 host+path 模型带我们走过容器化的第一个十年,但它的 annotation 主义、角色混乱、协议狭隘,早已撑不住现代流量治理的复杂度。Gateway API 用三层资源 + 三种角色 + 一致性测试,把"流量入口"从野路子变成了工程标准。
对工程师的务实建议:
- 新集群直接上 Gateway API,别再新建 Ingress Nginx。Ingress Nginx 已 EOL,安全补丁不再有保障。
- 存量迁移用
ingress2gateway起头,人工收尾。工具能覆盖 70% 的标准路由,剩下 30% 私有 annotation 需要你升级成 filter / BackendTrafficPolicy。 - 把路由纳入 GitOps。Gateway API 的声明式本质,让 HTTPRoute 和你的业务 YAML 一样可以 review、可以回滚、可以审计。
- 多租户/平台场景用 client-go 动态编排,把"路由即代码"变成平台能力。
更重要的是它在指向的未来——GAMMA 计划(Gateway API for Service Mesh)。它的目标是:用同一套 Gateway API 资源,既描述"南北向"(外部→集群)入口,也描述"东西向"(服务→服务)流量。一旦成熟,服务网格那套复杂的 CRD(VirtualService、DestinationRule…)有望被 Gateway API 统一收编。届时,"网关"和"网格"将不再是两套系统、两套心智,而是同一套标准下的两种部署形态。
2026 年,是 Ingress 谢幕的年份,也是流量治理真正标准化的起点。现在动手迁移,刚好赶在下一波复杂度爆炸之前,把地基打牢。
参考资料:Kubernetes SIG-Network Gateway API 官方文档(v1.2)、Envoy Gateway v1.3 文档、ingress2gateway 项目 README、CNCF Conformance Profiles 规范。本文所有 YAML 与 Go 代码均可在 K8s ≥ 1.25 环境按步骤复现。