Skip to content

필사 모드: Kubernetes Gateway API 实战指南:从替代 Ingress 到 HTTPRoute、GRPCRoute、Envoy Gateway 生产部署

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
Kubernetes 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 采用基于角色的资源模型设计,把基础设施运维人员与应用开发者的关注点清晰地分离开来。

对比项IngressGateway API
资源模型单一 Ingress 资源GatewayClass / Gateway / Route 分离
角色分离不支持基础设施团队 / 平台团队 / 开发团队分离
协议支持仅 HTTP/HTTPSHTTP, 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 匹配同一路径时,必须理解其优先级规则:

  1. 最长的主机名优先
  2. 最长的路径优先
  3. Exact 匹配优先于 PathPrefix
  4. 条件相同时,创建时间较早的资源优先

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 的强大能力。建议采用并行运行策略安全地完成迁移,并且务必同时配置好监控与告警,以确保生产环境的稳定性。

参考资料

현재 단락 (1/594)

长期以来,Kubernetes Ingress 一直是把外部流量路由到集群内部的标准方式。但它的局限也很明显:不同实现依赖各自的注解、配置全部集中在单一资源上、不支持 gRPC 或 TCP 这类非 H...

작성 글자: 0원문 글자: 14,455작성 단락: 0/594