前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >在 TKE 使用 EnvoyGateway 流量网关

在 TKE 使用 EnvoyGateway 流量网关

原创
作者头像
imroc
发布2025-02-27 10:03:36
发布2025-02-27 10:03:36
800
举报

概述

EnvoyGateway 是基于 Envoy 实现 Gateway API 的 Kubernetes 网关,你可以通过定义 Gateway API 中定义的 GatewayHTTPRoute 等资源来管理 Kubernetes 的南北向流量。

本文将介绍如何在 TKE 上安装 EnvoyGateway 并使用 Gateway API 来接入和管理流量转发。

:::tip说明

Kubernetes 提供了 Ingress API 来接入七层南北向流量,但功能很弱,每种实现都带了不同的 annotation 来增强 Ingress 的能力,灵活性和扩展性也较差,在社区的推进下,推出了 Gateway API 作为更好的解决方案,解决 Ingress API 痛点的同时,还统一了四七层南北向流量,同时也支持服务网格的东西向流量(参考 GAMMA),各个云厂商以及开源代理软件都在积极适配 Gateway API,可参考 Gateway API 的实现列表,其中 Envoy Gateway 便是其中一个很流行的实现。

在 TKE 上使用 EnvoyGateway 相比自带的 CLB Ingress 还有一个明显的优势,就是多个转发规则资源(如HTTPRoute)可以复用同一个 CLB,且可以跨命名空间。CLB Ingress 必须将所有转发规则写到同一个 Ingress 资源中,不方便管理,且如果不同后端 Service 跨命名空间了,则无法用同一个 Ingress (CLB)来管理了。

:::

操作步骤

安装 EnvoyGateway

方法一:通过应用市场安装

TKE 应用市场 搜索或在 网络 分类中找到 envoygateway,点击【创建应用】,命名空间选 envoy-gateway-system,若没有则先新建一个,完成其余配置后点击【创建】即可将 envoygateway 安装到集群中。

方法二:通过 Helm 安装

首先确保本机安装了 helm 并能操作 TKE 集群,参考 本地 Helm 客户端连接集群

然后再参考 EnvoyGateway 官方文档 使用 Helm 安装 进行安装。

配置 kubectl 访问集群

EnvoyGateway 使用的是 Gateway API 而不是 Ingress API,在 TKE 控制台无法直接创建,可通过 kubectl 命令进行创建,参考 连接集群 这篇文档配置 kubectl。

创建 GatewayClass

类似 Ingress 需要指定 IngressClass,Gateway API 中每个 Gateway 都需要引用一个 GatewayClassGatewayClass 相当于是网关实例除监听器外的配置(如部署方式、网关 Pod 的 template、副本数量、关联的 Service 等),所以先创建一个 GatewayClass

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller

GatewayClass 是 non-namespaced 资源,无需指定命名空间。

创建 Gateway

每个 Gateway 对应一个 CLB,在 Gateway 上声明端口相当于在 CLB 上创建响应协议的监听器:

:::tip说明

Gateway 的所有字段参考 API Specification: Gateway

:::

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: test-gw
  namespace: test
spec:
  gatewayClassName: eg
  listeners:
  - name: http
    protocol: HTTP
    port: 8080
    allowedRoutes:
      namespaces:
        from: All

Gateway 可以指定命名空间,可以被 HTTPRoute 等路由规则跨命名空间引用。

Gateway 创建后,EnvoyGateway 会自动为其创建一个 LoadBalancer 类型的 Service,也就是一个 CLB。在 TKE 上,LoadBalancer 类型的 Service 默认是一个公网 CLB,如果要自定义,可参考常见问题中的如何自定义 CLB

如何获取 Gateway 对应的 CLB 地址呢?可以通过 kubectl get gtw 查看:

代码语言:bash
复制
$ kubectl get gtw test-gw -n test
NAME      CLASS   ADDRESS         PROGRAMMED   AGE
test-gw   eg      139.155.64.52   True         358d

其中 ADDRESS 就是 CLB 的地址(IP 或域名)。

创建 HTTPRoute

HTTPRoute 用于定义 HTTP 转发规则(七层流量),也是 Gateway API 中最常用的转发规则,类似 Ingress API 中的 Ingress 资源。

下面给出一个示例:

:::tip说明

HTTPRoute 的所有字段参考API Specification: HTTPRoute

:::

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: nginx
  namespace: test
spec:
  parentRefs:
  - name: test-gw
    namespace: test
  hostnames:
  - "test.example.com"
  rules:
  - backendRefs:
    - name: nginx
      port: 80

:::info注意

  1. parentRefs 中指定要引用 Gateway(CLB),表示将该规则应用到这个 Gateway 中。
  2. hostnames 定义转发规则使用的的域名,确保该域名解析到 Gateway 对应的 CLB,这样可以通过域名访问集群内的服务。
  3. backendRefs 定义该条转发规则对应的后端 Service。

:::

创建 TCPRoute 和 UDPRoute

TCPRouteUDPRoute 用于定义 TCP 和 UDP 转发规则(四层流量),类似 LoadBalancer 类型的 Service

下面是 TCPRoute 的示例:

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - namespace: test
    name: test-gw
    sectionName: foo
  rules:
  - backendRefs:
    - name: foo
      port: 6000

:::info注意

  1. parentRefs 指定要引用的Gateway(CLB),表示将该 TCP 要监听到这个 Gateway 中。通常只使用 Gateway 中的一个端口,所以指定 sectionName 来指定使用哪个监听器暴露。
  2. backendRefs 定义该条转发规则对应的后端 Service。

:::

下面是 UDPRoute 的示例,与 TCPRoute 类似:

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
  name: bar
spec:
  parentRefs:
  - namespace: test
    name: test-gw
    sectionName: bar
  rules:
  - backendRefs:
    - name: bar
      port: 6000

引用的 Gateway 示例:

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: test-gw
  namespace: test
spec:
  gatewayClassName: eg
  listeners:
  - name: foo
    protocol: TCP
    port: 6000
    allowedRoutes:
      namespaces:
        from: All
  - name: bar
    protocol: UDP
    port: 6000
    allowedRoutes:
      namespaces:
        from: All

常见问题

如何自定义 CLB?

可通过创建 EnvoyProxy 自定义资源来自定义,下面是示例:

代码语言:yaml showLineNumbers
复制
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: proxy-config
  namespace: test
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyDeployment:
        replicas: 1
        container:
          resources:
            requests:
              tke.cloud.tencent.com/eni-ip: "1"
            limits:
              tke.cloud.tencent.com/eni-ip: "1"
        pod:
          annotations:
            tke.cloud.tencent.com/networks: tke-route-eni
      envoyService:
        annotations:
          service.kubernetes.io/tke-existed-lbid: lb-5nhlk3nr
          service.cloud.tencent.com/direct-access: "true"

以上示例中:

  • 显式声明使用 VPC-CNI 网络模式且启用 CLB 直连 Pod。
  • 使用已有 CLB,指定了 CLB 的 ID。

相应的,GatewayClass 中需引用该 EnvoyProxy 配置:

代码语言:yaml showLineNumbers
复制
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: proxy-config
    namespace: test

更多 CLB 相关的自定义可参考 Service Annotation 说明

举几个常见的自定义例子:

  1. 通过 service.cloud.tencent.com/specify-protocol 注解来修改监听器协议为 HTTPS 并正确引用 SSL 证书,以便让 CLB 能够接入 腾讯云 WAF
  2. 通过 service.kubernetes.io/qcloud-loadbalancer-internal-subnetid 注解指定 CLB 内网 IP,实现自动创建内网 CLB 来接入流量。
  3. 通过 service.kubernetes.io/service.extensiveParameters 注解自定义自动创建的 CLB 更多属性,如指定运营商、带宽上限、实例规格、网络计费模式等。

多个 HTTPRoute 如何复用同一个 CLB?

通常一个 Gateway 对象就对应一个 CLB,只要不同 HTTPRouteparentRefs 引用的是同一个 Gateway 对象,那么它们就会复用同一个 CLB。

:::info注意

如果多个 HTTPRoute 复用同一个 CLB,确保它们定义的 HTTP 规则不要冲突,否则可能转发行为可能不符预期。

:::

下面给个示例,第一个 HTTPRoute,引用 Gateway test-gw,使用域名 test1.example.com

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: test1
  namespace: test
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: test-gw
      namespace: test
  hostnames:
    - "test1.example.com"
  rules:
    - backendRefs:
        - group: ""
          kind: Service
          name: test1
          port: 80

第二个 HTTPRoute,也引用 Gateway test-gw,域名则使用 test2.example.com

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: test2
  namespace: test
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: test-gw
      namespace: test
  hostnames:
    - "test2.example.com"
  rules:
    - backendRefs:
        - group: ""
          kind: Service
          name: test2
          port: 80

如何实现四七层共用同一个 CLB?

使用 TKE 自带的 LoadBalancer 类型的 Service,可以实现多个 Service 复用同一个 CLB,也就是多个四层端口(TCP/UDP)复用同一个 CLB;使用 TKE 自带的 Ingress (CLB Ingress),无法与任何其它 IngressLoadBalancer 类型的 Service 复用同一个 CLB。所以,如果需要实现四七层共用同一个 CLB,直接使用 TKE 自带的 CLB Service 和 CLB Ingress 无法实现,而如果你安装了 EnvoyGateway 的话就可以实现。

下面给个示例, 首先 Gateway 的监听器声明四层和七层的端口:

:::tip注意

使用 name 给每个监听器取个名字,方便后续通过 sectionName 引用。

:::

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: test-gw
  namespace: test
spec:
  gatewayClassName: eg
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        group: ""
        name: https-cert
  - name: tcp-6000
    protocol: TCP
    port: 6000
    allowedRoutes:
      namespaces:
        from: All
  - name: udp-6000
    protocol: UDP
    port: 6000
    allowedRoutes:
      namespaces:
        from: All

HTTPRoute 里使用 Gateway 里的七层监听器(80 和 443):

:::tip注意

使用 sectionName 指定具体要绑定的监听器。

:::

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: test
  namespace: test
spec:
  parentRefs:
  - name: test-gw
    namespace: test
    sectionName: http
  - name: test-gw
    namespace: test
    sectionName: https
  hostnames:
  - "test.example.com"
  rules:
  - backendRefs:
    - group: ""
      kind: Service
      name: nginx
      port: 80

TCPRouteUDPRoute 里使用 Gateway 里的四层监听器(TCP/6000 和 UDP/6000):

:::tip注意

HTTPRoute 一样,使用 sectionName 指定具体要绑定的监听器。

:::

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - namespace: test
    name: test-gw
    sectionName: tcp-6000
  rules:
  - backendRefs:
    - name: foo
      port: 6000
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - namespace: test
    name: test-gw
    sectionName: udp-6000
  rules:
  - backendRefs:
    - name: foo
      port: 6000

如何实现自动重定向?

通过配置 HTTPRoutefilters 可实现自动重定向,下面给出示例。

路径前缀 /api/v1 替换成 /apis/v1

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-api-v1
  namespace: test
spec:
  hostnames:
  - test.example.com
  parentRefs:
  - name: test-gw
    namespace: test
    sectionName: https
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /apis/v1
        statusCode: 301

http://test.example.com/api/v1/pods 会被重定向到 http://test.example.com/apis/v1/pods

/foo 开头的统一重定向到 /bar

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-api-v1
  namespace: test
spec:
  hostnames:
  - test.example.com
  parentRefs:
  - name: test-gw
    namespace: test
    sectionName: https
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /foo
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplaceFullPath
          replaceFullPath: /bar
        statusCode: 301

https://test.example.com/foo/cayennehttps://test.example.com/foo/paprika 都会被重定向到 https://test.example.com/bar

HTTP 重定向到 HTTPS:

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-https
  namespace: test
spec:
  hostnames:
  - test.example.com
  parentRefs:
  - name: test-gw
    namespace: test
    sectionName: http
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301
        port: 443

http://test.example.com/foo 会被重定向到 https://test.example.com/foo

如何配置 HTTPS 或 TLS?

将证书和密钥存储在 Kubernetes 的 Secret 中:

:::tip说明

如果不想手动管理证书,希望证书自动签发,可考虑使用 cert-manager 来自动签发。参考 使用 cert-manager 为 DNSPod 的域名签发免费证书

:::

代码语言:yaml
复制
apiVersion: v1
kind: Secret
metadata:
  name: test-cert
  namespace: test
type: kubernetes.io/tls
data:
  tls.crt: ***
  tls.key: ***

Gateway 的 listeners 中配置 TLS(HTTPS 或 TLS 协议),tls 字段里引用证书 Secret:

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: test-gw
  namespace: test
spec:
  gatewayClassName: eg
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        group: ""
        name: test-cert
  - name: tls
    protocol: TLS
    port: 9443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        group: ""
        name: test-cert

能否使用腾讯云上的 SSL 证书?

Gateway 引用的证书是 K8S 的证书 Secret,不能直接使用上传到腾讯云 SSL 证书管理的证书。

可以考虑将 SSL 证书导出为 pem 格式的证书,然后使用 kubectl 命令上传到 K8S 集群。

如何修改 HTTP Header?

HTTPRoute 中使用 RequestHeaderModifier 这个 filter 可以修改 HTTP 请求的 Header。

以下是修改请求 Header 的例子。

:::tip说明

对路径以 /foo 开头的请求修改 Header。

:::

增加 Header(使用 add):

代码语言:yaml
复制
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: test
  name: foo-add-header
spec:
  hostnames:
  - test.example.com
  parentRefs:
  - name: test-gw
    namespace: test
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /foo
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: my-header-name
          value: my-header-value
    backendRefs:
    - name: foo
      port: 8080

修改 Header(使用 set):

代码语言:yaml
复制
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        set:
        - name: my-header-name
          value: my-header-value

删除 Header(使用 remove):

代码语言:yaml
复制
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        remove: ["x-request-id"]

如果要改响应的 Header 也是类似的,RequestHeaderModifier 改成 ResponseHeaderModifier 即可:

代码语言:yaml
复制
    filters:
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        add:
        - name: X-Header-Add-1
          value: header-add-1
        - name: X-Header-Add-2
          value: header-add-2
        - name: X-Header-Add-3
          value: header-add-3

探索更多用法

Gateway API 非常强大,可实现很多复杂的功能,如基于权重、header、cookie 等特征的路由、灰度发布、流量镜像、URL重定向与重写、TLS 路由、GRPC 路由等,更详细的用法参考 Gateway API 官方文档

EnvoyGateway 也支持了 Gateway API 之外的一些特有的高级能力,可参考 EnvoyGateway 官方文档

参考资料

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 操作步骤
    • 安装 EnvoyGateway
      • 方法一:通过应用市场安装
      • 方法二:通过 Helm 安装
    • 配置 kubectl 访问集群
    • 创建 GatewayClass
    • 创建 Gateway
    • 创建 HTTPRoute
    • 创建 TCPRoute 和 UDPRoute
  • 常见问题
    • 如何自定义 CLB?
    • 多个 HTTPRoute 如何复用同一个 CLB?
    • 如何实现四七层共用同一个 CLB?
    • 如何实现自动重定向?
    • 如何配置 HTTPS 或 TLS?
    • 能否使用腾讯云上的 SSL 证书?
    • 如何修改 HTTP Header?
  • 探索更多用法
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档