Kubernetes 网络正在从 Ingress 资源向 Gateway API 演进,这不是趋势预测——Gateway API 已经进入 GA,各大云厂商和社区项目都在围绕它构建新功能。对于已经在生产环境跑 Ingress NGINX 的团队,真正的问题不是"要不要换",而是"怎么换才能不中断流量"。
为什么选 Envoy Gateway
Ingress NGINX 在简单场景下足够好用,但它的扩展模型依赖 Lua 和自定义模板,配置变更需要 reload,高级路由能力有限。Envoy Gateway 是 Envoy 项目的官方 Gateway API 实现,几个关键差异直接影响迁移决策:
- 原生 Gateway API 支持:不需要额外 CRD,直接使用
GatewayClass、Gateway、HTTPRoute等标准资源,未来升级不需要改配置格式。 - 增量配置推送:Envoy 的 xDS 协议支持增量更新,路由变更不需要重启或 reload 数据面进程,配置生效延迟在毫秒级。
- 可观测性内置:Envoy 的访问日志、指标、追踪输出格式丰富,Envoy Gateway 开箱即用就暴露了 Prometheus 指标端口。
如果你的集群已经在用 Envoy(比如作为 Istio 的数据面),Envoy Gateway 可以复用运维经验和调试工具链,迁移的学习成本更低。
双写并行:零停机迁移的核心策略
零停机迁移的关键原则是同时运行两套控制器,逐步把流量从旧入口切到新入口,而不是一次性切换。整个流程分三个阶段:
- 部署 Envoy Gateway,但不接管流量——先让它跑起来,验证配置翻译正确。
- 双写 Ingress 和 HTTPRoute——同一组后端服务同时被两种资源指向,通过 DNS 或外部 LB 逐步把外部流量切到 Envoy Gateway 的入口。
- 确认流量完全走新入口后,清理 Ingress 资源和 NGINX 控制器。
下面用一个具体示例走完这个流程。
实操示例:一个服务的完整迁移
假设集群里有一个 demo-app 服务,当前通过 Ingress NGINX 暴露:
# 原有 Ingress 资源
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-app
namespace: demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: demo.example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: demo-app
port:
number: 8080
第一步:安装 Envoy Gateway
用 Helm 快速安装,先只部署控制器和数据面,不创建 Gateway 资源:
helm repo add envoy-gateway https://envoy-gateway.github.io/charts
helm repo update
helm install envoy-gateway envoy-gateway/envoy-gateway \
--namespace envoy-gateway-system \
--create-namespace \
--set gateway.gatewayClassName=eg \
--wait
安装完成后,确认控制器和数据面 Pod 都正常运行:
kubectl get pods -n envoy-gateway-system
# 预期看到 envoy-gateway-controller 和 envoy 数据面 Pod
第二步:创建 Gateway 和 HTTPRoute(双写阶段)
把上面的 Ingress 规则翻译成 Gateway API 资源。注意 rewrite-target 注解在 HTTPRoute 里用 filters 实现:
# Gateway 资源:声明监听端口和协议
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: demo-gateway
namespace: demo
spec:
gatewayClassName: eg
listeners:
- name: http
port: 80
protocol: HTTP
hostname: demo.example.com
allowedRoutes:
namespaces:
from: Same
---
# HTTPRoute 资源:等效于原 Ingress 的路由规则
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-app-route
namespace: demo
spec:
parentRefs:
- name: demo-gateway
sectionName: http
hostnames:
- demo.example.com
rules:
- matches:
- path:
type: RegularExpression
value: /api(/|$)(.*)
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /$2
backendRefs:
- name: demo-app
port: 8080
应用这两个资源:
kubectl apply -f demo-gateway.yaml -f demo-httproute.yaml -n demo
此时 Ingress NGINX 和 Envoy Gateway 同时指向同一个后端服务。Envoy Gateway 会自动创建一个 LoadBalancer 类型的 Service 作为入口:
kubectl get gateway demo-gateway -n demo -o jsonpath='{.status.addresses[0].value}'
# 输出 Envoy Gateway 的外部 IP,记为 ENVOY_IP
第三步:逐步切流量
不要一次性改 DNS。用权重切流的方式更安全:
- 先在 DNS(或外部 LB)添加一条指向
ENVOY_IP的记录,权重设为 10%。 - 观察 Envoy Gateway 的指标和后端服务日志,确认请求正常到达:
# 查看 Envoy Gateway 的 Prometheus 指标
kubectl port-forward -n envoy-gateway-system svc/envoy-gateway-metrics 19001:19001
# 另一个终端
curl -s http://localhost:19001/metrics | grep envoy_http_downstream_rq_completed
- 逐步提高权重:10% → 30% → 50% → 100%。每一步至少观察一个完整业务周期(包含峰值时段)。
- 当 DNS 100% 指向
ENVOY_IP后,保留双写状态运行 24-48 小时作为回退窗口。
第四步:清理旧资源
确认流量完全走 Envoy Gateway 后:
# 删除 Ingress 资源
kubectl delete ingress demo-app -n demo
# 卸载 Ingress NGINX 控制器(根据你的安装方式调整)
helm uninstall ingress-nginx -n ingress-nginx
# 可选:清理 namespace
kubectl delete namespace ingress-nginx
需要注意的坑
迁移过程中有几个容易踩到的点:
注解翻译不是一对一的。Ingress NGINX 有大量特定注解(nginx.ingress.kubernetes.io/*),部分功能在 Gateway API 里没有直接等效项。比如 proxy-buffer-size、affinity-mode 这些调优参数,Envoy Gateway 目前通过 EnvoyProxy 自定义资源来覆盖。迁移前先列出你用到的所有注解,逐条确认翻译方案。
TLS 配置要提前迁移。如果你的 Ingress 用了 TLS,Gateway API 的 TLS 配置放在 Gateway 资源的 listeners 里,证书引用方式不同。建议先在非生产环境验证 TLS 路径。
Webhook 和自定义路径匹配。Ingress NGINX 的 pathType: ImplementationSpecific 允许写正则,Gateway API 的 RegularExpression 类型等效但语义更明确。如果你的正则比较复杂,建议在迁移前用 httproute 的 dry-run 校验:
kubectl apply --dry-run=server -f demo-httproute.yaml -n demo
迁移前检查清单
在动手之前,确认以下事项:
| 检查项 | 说明 |
|---|---|
| 列出所有 Ingress 注解 | 逐条确认在 Envoy Gateway 里的等效配置 |
| TLS 证书引用方式 | Gateway API 用 Secret + Gateway listener 组合,和 Ingress 不同 |
| 外部流量入口类型 | LoadBalancer / NodePort / 外部 LB,决定切流方式 |
| 监控覆盖 | Envoy Gateway 的指标端口(19001)是否接入 Prometheus |
| 回退方案 | DNS 切流期间保留 Ingress 双写,至少 24 小时回退窗口 |
| 团队熟悉度 | Envoy 的调试命令(curl admin:15000/config_dump)和日志格式需要提前熟悉 |
零停机迁移的本质是"并行运行 + 逐步切流",而不是"配置翻译 + 一键替换"。把时间花在注解清单梳理和切流观察上,比花在配置格式转换上更值得——后者可以脚本化,前者需要逐条判断。