从 Ingress NGINX 到 Envoy Gateway:零停机迁移实战

2026-05-25 23 预计阅读时间:1 分钟
来源:cncf.io AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

Kubernetes 网络正在从 Ingress 资源向 Gateway API 演进,这不是趋势预测——Gateway API 已经进入 GA,各大云厂商和社区项目都在围绕它构建新功能。对于已经在生产环境跑 Ingress NGINX 的团队,真正的问题不是"要不要换",而是"怎么换才能不中断流量"。

为什么选 Envoy Gateway

Ingress NGINX 在简单场景下足够好用,但它的扩展模型依赖 Lua 和自定义模板,配置变更需要 reload,高级路由能力有限。Envoy Gateway 是 Envoy 项目的官方 Gateway API 实现,几个关键差异直接影响迁移决策:

  • 原生 Gateway API 支持:不需要额外 CRD,直接使用 GatewayClassGatewayHTTPRoute 等标准资源,未来升级不需要改配置格式。
  • 增量配置推送:Envoy 的 xDS 协议支持增量更新,路由变更不需要重启或 reload 数据面进程,配置生效延迟在毫秒级。
  • 可观测性内置:Envoy 的访问日志、指标、追踪输出格式丰富,Envoy Gateway 开箱即用就暴露了 Prometheus 指标端口。

如果你的集群已经在用 Envoy(比如作为 Istio 的数据面),Envoy Gateway 可以复用运维经验和调试工具链,迁移的学习成本更低。

双写并行:零停机迁移的核心策略

零停机迁移的关键原则是同时运行两套控制器,逐步把流量从旧入口切到新入口,而不是一次性切换。整个流程分三个阶段:

  1. 部署 Envoy Gateway,但不接管流量——先让它跑起来,验证配置翻译正确。
  2. 双写 Ingress 和 HTTPRoute——同一组后端服务同时被两种资源指向,通过 DNS 或外部 LB 逐步把外部流量切到 Envoy Gateway 的入口。
  3. 确认流量完全走新入口后,清理 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。用权重切流的方式更安全:

  1. 先在 DNS(或外部 LB)添加一条指向 ENVOY_IP 的记录,权重设为 10%。
  2. 观察 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
  1. 逐步提高权重:10% → 30% → 50% → 100%。每一步至少观察一个完整业务周期(包含峰值时段)。
  2. 当 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-sizeaffinity-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)和日志格式需要提前熟悉

零停机迁移的本质是"并行运行 + 逐步切流",而不是"配置翻译 + 一键替换"。把时间花在注解清单梳理和切流观察上,比花在配置格式转换上更值得——后者可以脚本化,前者需要逐条判断。


相关推荐