- Published on
Kubernetes Gateway API 实战指南:从替代 Ingress 到 HTTPRoute、GRPCRoute、Envoy Gateway 生产部署
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 前言
- Gateway API 与 Ingress 对比
- Envoy Gateway 安装与配置
- HTTPRoute 深度实践
- GRPCRoute 生产配置
- TLS 终止与证书管理
- Envoy Gateway 限流
- 通过 ReferenceGrant 实现跨命名空间路由
- 从 Ingress 迁移到 Gateway API
- 监控配置
- 运维注意事项
- 故障案例与恢复流程
- 结语
- 参考资料

前言
长期以来,Kubernetes Ingress 一直是把外部流量路由到集群内部的标准方式。但它的局限也很明显:不同实现依赖各自的注解、配置全部集中在单一资源上、不支持 gRPC 或 TCP 这类非 HTTP 协议等等。Kubernetes 社区为了解决这些问题设计了Gateway API,目前在 v1.2 中 HTTPRoute 与 GRPCRoute 均已进入 GA(Generally Available)状态,可以在生产环境中稳定使用。
尤其是随着 Ingress NGINX 正式宣布退役(2026 年 3 月之后仅提供尽力而为的维护),迁移到 Gateway API 已经不再是可选项,而是必选项。本文以 Envoy Gateway 作为实现,配合实战代码讲解 HTTPRoute、GRPCRoute、TLS 终止、流量分割、基于请求头的路由乃至限流等生产环境所需的全部配置。
Gateway API 与 Ingress 对比
架构上的差异
Gateway API 采用基于角色的资源模型设计,把基础设施运维人员与应用开发者的关注点清晰地分离开来。
| 对比项 | Ingress | Gateway API |
|---|---|---|
| 资源模型 | 单一 Ingress 资源 | GatewayClass / Gateway / Route 分离 |
| 角色分离 | 不支持 | 基础设施团队 / 平台团队 / 开发团队分离 |
| 协议支持 | 仅 HTTP/HTTPS | HTTP, gRPC, TCP, UDP, TLS |
| 配置方式 | 各实现自定义注解 | 标准化的规范 |
| 跨命名空间 | 不支持 | 通过 ReferenceGrant 支持 |
| 流量分割 | 依赖注解 | 原生基于 weight |
| 请求头匹配 | 各实现不一致 | 包含在标准规范中 |
| GA 状态 | 稳定但计划退役 | v1.2 GA (HTTPRoute, GRPCRoute) |
资源分层结构
下面来看一下 Gateway API 的三层资源模型。
# 第 1 层:GatewayClass - 由基础设施提供方管理(集群作用域)
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy-gateway
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
# 第 2 层:Gateway - 由平台团队管理(命名空间作用域)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: infra-gateway
spec:
gatewayClassName: envoy-gateway
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: wildcard-tls-cert
- name: http
protocol: HTTP
port: 80
---
# 第 3 层:HTTPRoute - 由开发团队管理(各应用命名空间)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: app-team-a
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
sectionName: https
hostnames:
- 'api.example.com'
rules:
- matches:
- path:
type: PathPrefix
value: /v1/users
backendRefs:
- name: user-service
port: 8080
Envoy Gateway 安装与配置
通过 Helm 安装
# 安装 Envoy Gateway Helm chart
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.3.0 \
-n envoy-gateway-system \
--create-namespace \
--set config.envoyGateway.logging.level.default=info
# 确认安装结果
kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass
# 确认 CRD
kubectl get crd | grep gateway.networking.k8s.io
创建 GatewayClass 与 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy-production
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
parametersRef:
group: gateway.envoyproxy.io
kind: EnvoyProxy
name: production-config
namespace: envoy-gateway-system
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
name: production-config
namespace: envoy-gateway-system
spec:
provider:
type: Kubernetes
kubernetes:
envoyDeployment:
replicas: 3
pod:
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '19001'
container:
resources:
requests:
cpu: '500m'
memory: '512Mi'
limits:
cpu: '2000m'
memory: '2Gi'
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: infra-gateway
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
gatewayClassName: envoy-production
listeners:
- name: https-wildcard
protocol: HTTPS
port: 443
hostname: '*.example.com'
tls:
mode: Terminate
certificateRefs:
- name: wildcard-example-tls
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: 'true'
- name: http-redirect
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
HTTPRoute 深度实践
基于路径的路由
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-routes
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
sectionName: https-wildcard
hostnames:
- 'app.example.com'
rules:
# Exact 匹配 - 优先级最高
- matches:
- path:
type: Exact
value: /healthz
backendRefs:
- name: health-check-service
port: 8080
# PathPrefix 匹配 - 按 API 版本路由
- matches:
- path:
type: PathPrefix
value: /api/v2
backendRefs:
- name: api-v2-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /api/v1
backendRefs:
- name: api-v1-service
port: 8080
# RegularExpression 匹配
- matches:
- path:
type: RegularExpression
value: '/users/[0-9]+/profile'
backendRefs:
- name: user-profile-service
port: 8080
基于请求头的路由
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-based-routing
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'api.example.com'
rules:
# 根据特定请求头的取值路由到不同后端
- matches:
- headers:
- name: x-api-version
value: 'beta'
- name: x-user-tier
value: 'premium'
backendRefs:
- name: api-beta-premium
port: 8080
# 用于 A/B 测试的请求头路由
- matches:
- headers:
- name: x-experiment-group
value: 'treatment'
backendRefs:
- name: api-experiment
port: 8080
# 默认路由(没有匹配条件)
- backendRefs:
- name: api-stable
port: 8080
流量分割(金丝雀发布)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'app.example.com'
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
# 稳定版本:90% 流量
- name: app-stable
port: 8080
weight: 90
# 金丝雀版本:10% 流量
- name: app-canary
port: 8080
weight: 10
HTTP 重定向与 URL 重写
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: redirect-and-rewrite
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'app.example.com'
rules:
# HTTP -> HTTPS 重定向
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: url-rewrite
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'api.example.com'
rules:
# /old-api/* -> /new-api/* 路径重写
- matches:
- path:
type: PathPrefix
value: /old-api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /new-api
backendRefs:
- name: api-service
port: 8080
GRPCRoute 生产配置
基本的 GRPCRoute 设置
GRPCRoute 在 Gateway API v1.1 中升级为 GA,并且在 v1.2 中原有的 v1alpha2 版本已被完全移除。
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: order-service-route
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
sectionName: https-wildcard
hostnames:
- 'grpc.example.com'
rules:
# 基于服务的匹配
- matches:
- method:
service: 'order.v1.OrderService'
backendRefs:
- name: order-service-grpc
port: 50051
# 基于方法的匹配
- matches:
- method:
service: 'order.v1.OrderService'
method: 'CreateOrder'
backendRefs:
- name: order-write-service
port: 50051
# 基于请求头的匹配
- matches:
- headers:
- name: x-region
value: 'asia'
method:
service: 'order.v1.OrderService'
backendRefs:
- name: order-service-asia
port: 50051
GRPCRoute 流量分割
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-canary
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'grpc.example.com'
rules:
- matches:
- method:
service: 'payment.v1.PaymentService'
backendRefs:
- name: payment-service-stable
port: 50051
weight: 95
- name: payment-service-canary
port: 50051
weight: 5
TLS 终止与证书管理
对接 cert-manager
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: production-gateway
namespace: infra-gateway
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-example-tls
namespace: infra-gateway
spec:
secretName: wildcard-example-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- '*.example.com'
- 'example.com'
mTLS 配置(Envoy Gateway BackendTLSPolicy)
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
name: backend-mtls
namespace: production
spec:
targetRefs:
- group: ''
kind: Service
name: secure-backend
validation:
caCertificateRefs:
- name: backend-ca-cert
group: ''
kind: ConfigMap
hostname: secure-backend.production.svc.cluster.local
Envoy Gateway 限流
全局限流
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: global-rate-limit
namespace: infra-gateway
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: production-gateway
rateLimit:
type: Global
global:
rules:
- clientSelectors:
- headers:
- name: x-api-key
type: Distinct
limit:
requests: 100
unit: Minute
- limit:
requests: 1000
unit: Minute
按路径限流
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: api-rate-limit
namespace: production
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
rateLimit:
type: Global
global:
rules:
- clientSelectors:
- headers:
- name: x-user-tier
value: 'free'
limit:
requests: 10
unit: Minute
- clientSelectors:
- headers:
- name: x-user-tier
value: 'premium'
limit:
requests: 1000
unit: Minute
通过 ReferenceGrant 实现跨命名空间路由
# 允许 app-team-a 命名空间中的 HTTPRoute
# 引用 shared-services 命名空间中的 Service
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-cross-ns-routing
namespace: shared-services
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-a
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-b
to:
- group: ''
kind: Service
从 Ingress 迁移到 Gateway API
使用 ingress2gateway 工具
# 安装 ingress2gateway
go install github.com/kubernetes-sigs/ingress2gateway@latest
# 把已有的 Ingress 资源转换为 Gateway API
ingress2gateway print \
--input-file existing-ingress.yaml \
--providers ingress-nginx \
--all-resources
# 直接在集群中转换
ingress2gateway print \
--providers ingress-nginx \
--all-resources \
--namespace production
迁移策略:并行运行
# 已有的 Ingress(保留)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: legacy-app-ingress
namespace: production
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 8080
---
# 新的 Gateway API HTTPRoute(并行部署)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: infra-gateway
hostnames:
- 'app.example.com'
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-service
port: 8080
分阶段迁移步骤
# 第 1 步:确认 Gateway API CRD 已安装
kubectl get crd gateways.gateway.networking.k8s.io
# 第 2 步:安装 Envoy Gateway
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.3.0 \
-n envoy-gateway-system --create-namespace
# 第 3 步:创建 GatewayClass/Gateway
kubectl apply -f gateway-class.yaml
kubectl apply -f gateway.yaml
# 第 4 步:把已有 Ingress 转换为 HTTPRoute
ingress2gateway print --providers ingress-nginx --all-resources > routes.yaml
# 第 5 步:部署转换后的 HTTPRoute(并行运行)
kubectl apply -f routes.yaml
# 第 6 步:把 DNS 切换到新的 Gateway LoadBalancer
GATEWAY_IP=$(kubectl get gateway production-gateway -n infra-gateway \
-o jsonpath='{.status.addresses[0].value}')
echo "Update DNS A record to: $GATEWAY_IP"
# 第 7 步:观察流量后移除旧的 Ingress
kubectl delete ingress legacy-app-ingress -n production
监控配置
Prometheus 指标采集
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: envoy-gateway-metrics
namespace: envoy-gateway-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: envoy
endpoints:
- port: metrics
interval: 15s
path: /stats/prometheus
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: gateway-api-alerts
namespace: monitoring
spec:
groups:
- name: gateway-api
rules:
- alert: GatewayHighErrorRate
expr: |
sum(rate(envoy_http_downstream_rq_xx{envoy_response_code_class="5"}[5m])) by (envoy_http_conn_manager_prefix)
/
sum(rate(envoy_http_downstream_rq_total[5m])) by (envoy_http_conn_manager_prefix)
> 0.05
for: 5m
labels:
severity: critical
annotations:
summary: 'Gateway error rate exceeds 5%'
- alert: GatewayHighLatency
expr: |
histogram_quantile(0.99,
sum(rate(envoy_http_downstream_rq_time_bucket[5m])) by (le, envoy_http_conn_manager_prefix)
) > 1000
for: 5m
labels:
severity: warning
annotations:
summary: 'Gateway p99 latency exceeds 1s'
Grafana 仪表盘查询
# 确认主要的 Envoy 指标
# 每秒请求数
sum(rate(envoy_http_downstream_rq_total[5m])) by (envoy_http_conn_manager_prefix)
# 错误率(5xx)
sum(rate(envoy_http_downstream_rq_xx{envoy_response_code_class="5"}[5m]))
# 平均响应时间
sum(rate(envoy_http_downstream_rq_time_sum[5m])) / sum(rate(envoy_http_downstream_rq_time_count[5m]))
# 活跃连接数
envoy_http_downstream_cx_active
运维注意事项
1. 设置资源限制
在生产环境中必须为 Envoy Proxy 设置资源限制。如果使用默认值运行,流量突增时可能发生 OOM(Out of Memory)。
2. 限制 Gateway 监听器数量
在一个 Gateway 上添加过多监听器会让 Envoy 配置变得臃肿,导致重载时间变长。建议按域名或按团队拆分 Gateway。
3. ReferenceGrant 最小权限
跨命名空间引用只在必要时开放,并且要尽可能具体地指定目标命名空间与资源。
4. HTTPRoute 优先级
当多个 HTTPRoute 匹配同一路径时,必须理解其优先级规则:
- 最长的主机名优先
- 最长的路径优先
- Exact 匹配优先于 PathPrefix
- 条件相同时,创建时间较早的资源优先
5. 应对 v1alpha2 的移除
Gateway API v1.2 中移除了 GRPCRoute 与 ReferenceGrant 的 v1alpha2 版本。如果还在使用 v1alpha2,必须迁移到 v1。
故障案例与恢复流程
案例 1:TLS 证书过期
# 症状:503 错误,TLS handshake 失败
# 诊断
kubectl get certificate -n infra-gateway
kubectl describe certificate wildcard-example-tls -n infra-gateway
# 恢复:让 cert-manager 强制续期
kubectl delete certificaterequest -n infra-gateway --all
kubectl annotate certificate wildcard-example-tls \
-n infra-gateway \
cert-manager.io/renew-before="720h" --overwrite
# 紧急情况:手动更换证书
kubectl create secret tls wildcard-example-tls \
--cert=fullchain.pem --key=privkey.pem \
-n infra-gateway --dry-run=client -o yaml | kubectl apply -f -
案例 2:Gateway 控制器故障
# 症状:新建的 HTTPRoute 不生效
# 诊断
kubectl get pods -n envoy-gateway-system
kubectl logs -n envoy-gateway-system deploy/envoy-gateway -f
# 确认 Envoy Proxy 状态
kubectl get pods -l app.kubernetes.io/name=envoy -A
# 恢复:重启控制器
kubectl rollout restart deployment/envoy-gateway -n envoy-gateway-system
# 确认 Gateway 状态
kubectl get gateway production-gateway -n infra-gateway -o yaml
案例 3:错误的 HTTPRoute 导致流量黑洞
# 症状:发往特定路径的请求全部返回 404
# 诊断:确认 HTTPRoute 状态
kubectl get httproute -A
kubectl describe httproute app-route -n production
# 在 status 中确认 Accepted/ResolvedRefs 条件
# 原因:backendRef 指向了并不存在的 Service
# 恢复:修正为正确的服务名后重新应用
kubectl apply -f corrected-httproute.yaml
# 确认 Envoy 配置已同步
kubectl exec -n envoy-gateway-system deploy/envoy-gateway -- \
curl -s localhost:19000/config_dump | python3 -m json.tool | head -100
案例 4:限流误触发
# 症状:正常用户也收到 429 Too Many Requests
# 诊断
kubectl get backendtrafficpolicy -A
kubectl describe backendtrafficpolicy global-rate-limit -n infra-gateway
# 确认基于 Redis 的全局限流器状态
kubectl logs -n envoy-gateway-system deploy/envoy-ratelimit
# 恢复:临时移除限流策略
kubectl delete backendtrafficpolicy global-rate-limit -n infra-gateway
# 恢复正常后重新应用修正过的策略
kubectl apply -f corrected-rate-limit.yaml
结语
Kubernetes Gateway API 克服了 Ingress 的局限,让基于角色的体系化流量管理成为可能。v1.2 中 HTTPRoute 与 GRPCRoute 都已经在 GA 状态下趋于稳定,而 Ingress NGINX 的退役也已临近,现在正是迁移的最佳时机。
选择 Envoy Gateway 作为实现,就可以通过 Gateway API 的标准接口来使用限流、认证、全局负载均衡等 Envoy 的强大能力。建议采用并行运行策略安全地完成迁移,并且务必同时配置好监控与告警,以确保生产环境的稳定性。