Skip to content

从 Ingress 迁移 ​

原文:https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/

Gateway API 是 Ingress API 的继任者。本指南提供从任何 Ingress 实现迁移到 Gateway API 的总体概览。内容聚焦于 Ingress 与 Gateway API 之间的核心概念、关键差异和功能映射,并给出一份手工转换示例。

IMPORTANT

你是 Ingress-NGINX 用户吗? ​

如果你专门在使用 Ingress-NGINX,我们推荐你额外阅读 Ingress-NGINX 迁移指南,里面有更具针对性的建议与资源。

本指南会帮助你完成转换。它会:

  • 解释你为何要切换到 Gateway API;
  • 描述 Ingress API 与 Gateway API 之间的关键差异;
  • 将 Ingress 的功能映射到 Gateway API 的功能;
  • 给出一个 Ingress 资源转换为 Gateway API 资源的示例;
  • 介绍用于自动转换的 ingress2gateway。

同时,它不会帮你做线上(in-place)迁移,也不会教你怎么转换你正在使用的 Ingress 控制器中那些实现特有的特性。此外,由于 Ingress API 只覆盖 HTTP/HTTPS 流量,本指南不会涉及 Gateway API 对其他协议的支持。

为什么要切换到 Gateway API ​

Ingress API 是 Kubernetes 中用于为 Service 配置外部 HTTP/HTTPS 负载均衡的标准方案。它被 Kubernetes 用户广泛采用,被厂商们良好支持,并有大量可用的 Ingress 控制器 实现。此外,诸如 cert-manager 和 ExternalDNS 等多个云原生项目也集成了 Ingress API。

然而,Ingress API 存在若干局限:

  • 特性有限:Ingress API 仅支持 TLS 终止和基于内容的简单 HTTP 路由。
  • 依赖注解进行扩展:注解方式的可扩展性导致可移植性差——每个实现都有自己一套支持的扩展,无法直接迁移到另一实现。
  • 权限模型不足:Ingress API 难以胜任多团队共享同一套负载均衡基础设施的多租户集群场景。

Gateway API 解决了这些限制,详见下一节。

更多内容可阅读 设计目标。

Ingress API 与 Gateway API 的关键差异 ​

Ingress API 与 Gateway API 之间有三大主要差异:

  • 角色(Personas)
  • 可用特性
  • 扩展方式(实现特有特性)

角色 ​

最初 Ingress API 只有一种资源类型 Ingress。因此它只有一种角色——用户——即 Ingress 资源的拥有者。Ingress 的特性让用户对应用如何暴露给外部客户端拥有很大控制权,包括 TLS 终止配置以及(部分 Ingress 控制器支持的)负载均衡基础设施的供给。这种程度的控制被称作"自助式(self-service)"模型。

与此同时,Ingress API 实际也内含两个隐式角色:负责提供和管理 Ingress 控制器的"基础设施提供者(provider-managed)",以及负责自管 Ingress 控制器的"集群运维人员(self-hosted)"。随着后期加入的 IngressClass 资源,基础设施提供者和集群运维人员变成了该资源的拥有者,也因此成为 Ingress API 的显式角色。

Gateway API 包含四个显式角色:应用开发者、应用管理员、集群运维人员和基础设施提供者。这样,你就可以摆脱"自助式"模型,把"用户"角色的责任拆分到这些角色身上(基础设施提供者除外):

  • 集群运维人员 / 应用管理员:定义外部客户端流量的入口点,包括 TLS 终止配置。
  • 应用开发者:定义连接到这些入口点的、针对自身应用的路由规则。

这种拆分契合多团队共享同一套负载均衡基础设施的常见组织结构。同时,你不一定要彻底放弃自助式模型——依然可以配置一个统一的 RBAC Role 来同时承担应用开发者、应用管理员、集群运维人员的责任。

下表总结了 Ingress API 角色与 Gateway API 角色之间的映射:

Ingress API 角色Gateway API 角色
User(用户)Application developer、Application admin、Cluster operator
Cluster operator(集群运维人员)Cluster operator(集群运维人员)
Infrastructure provider(基础设施提供者)Infrastructure provider(基础设施提供者)

可用特性 ​

Ingress API 只提供基础特性:TLS 终止和基于请求主机头与 URI 的 HTTP 内容路由。为了提供更多特性,Ingress 控制器通过注解 来支持它们——这些是 Ingress 资源的实现特有扩展。

注解式的扩展方式对 Ingress API 的用户带来两个负面后果:

  • 可移植性有限。因为有大量特性通过注解提供,所以在不同的 Ingress 控制器之间切换变得很困难,甚至不可能:你需要把一种实现的注解转换为另一种实现(且另一种实现可能压根不支持某些特性)。这限制了 Ingress API 的可移植性。
  • API 笨拙。注解是 key-value 字符串(不像 Ingress spec 那种结构化方案),而且是"贴"在整个资源顶部(而不是 spec 中与特性相关的位置)。当一个 Ingress 资源上叠了非常多注解时,Ingress API 用起来就会很别扭。

Gateway API 支持 Ingress 资源的全部特性,以及许多只有通过注解才能得到的特性。因此 Gateway API 比 Ingress API 更加可移植。此外,正如下一节将展示的,你将完全不需要使用任何注解,这也一并解决了"API 笨拙"的问题。

扩展方式 ​

Ingress API 有两个扩展点:

  • Ingress 资源上的注解(前文已介绍)。
  • Resource backends(资源后端):即把后端指定为 Service 以外资源的能力。

相比 Ingress API,Gateway API 已经非常丰富。但要配置一些高级特性(例如认证)以及一些跨数据平面但不可移植的通用特性(例如连接超时、健康检查),仍然需要依赖 Gateway API 的扩展机制。

Gateway API 的主要扩展点有:

  • 外部引用:例如 HTTPRouteFilter 可以通过 extensionRef 字段引用外部资源,从而配置实现特有的过滤器;BackendObjectReference 支持 Service 以外的后端资源;SecretObjectReference 支持 Secret 以外的资源。
  • 类型扩展:例如 HTTPPathMatch 中的 RegularExpression 类型。
  • Policy(策略):Gateway 实现可以定义自己的 Policy 资源来暴露认证等数据平面特性。Gateway API 不规定这些资源的具体内容,但规定了一套标准的用户体验。详见 Policy attachment 指南。与上面提到的"外部引用"相反,Policy 不会被 Gateway API 资源所引用;反过来,Policy 必须引用一个 Gateway API 资源。

注意:上述扩展点不包括 Gateway API 资源上的注解。对于 Gateway API 的实现来说,这种方式是强烈不推荐的。

Ingress API 特性到 Gateway API 特性的映射 ​

本节把 Ingress API 的特性映射到对应的 Gateway API 特性,覆盖三大领域:

  • 入口点(Entry points)
  • TLS 终止
  • 路由规则

入口点 ​

粗略地说,入口点是数据平面暴露给外部客户端的IP + 端口组合。

每个 Ingress 资源都有两个隐式入口点——一个用于 HTTP 流量,另一个用于 HTTPS 流量。这两个入口点由 Ingress 控制器提供。典型情况下,它们要么被所有 Ingress 资源共享,要么每个 Ingress 资源独享。

在 Gateway API 中,入口点必须通过 Gateway 资源显式定义。例如,如果你希望数据平面在 80 端口处理 HTTP 流量,就需要在 Gateway 资源中为该流量定义一个 listener。通常,一个 Gateway 实现会为每个 Gateway 资源提供一份独立的数据平面。

Gateway 资源由集群运维人员和应用管理员所拥有。

TLS 终止 ​

Ingress 资源通过 TLS 段 支持 TLS 终止,TLS 证书与私钥保存在 Secret 中。

在 Gateway API 中,TLS 终止是 Gateway listener 的一项属性,与 Ingress 类似,TLS 证书与私钥同样保存在 Secret 中。

由于 listener 是 Gateway 资源的一部分,因此 TLS 终止由集群运维人员和应用管理员所有。

路由规则 ​

Ingress 资源的基于路径的路由规则 直接映射到 HTTPRoute 的路由规则。

基于主机头的路由规则映射到 HTTPRoute 的 hostnames。但需要注意的是:在 Ingress 中,每个主机名各自有独立的路由规则;而在 HTTPRoute 中,路由规则对所有主机名统一适用。

Ingress API 使用"host"这个术语,而 Gateway API 使用"hostname"。本指南将使用 Gateway API 的术语来指代 Ingress 中的 host。

HTTPRoute 的 hostnames 必须与 Gateway listener 的 hostname 相匹配。否则,listener 会忽略那些不匹配的主机名所对应的路由规则。详见 HTTPRoute 文档。

HTTPRoute 由应用开发者所拥有。

下面三小节映射 Ingress 路由规则的其他特性。

规则合并与冲突解决 ​

通常,Ingress 控制器会合并所有 Ingress 资源的路由规则(除非它为每个 Ingress 资源各自提供一个数据平面),并解决规则之间可能出现的冲突。然而,Ingress API 没有规定合并与冲突解决的具体行为,因此不同 Ingress 控制器的实现可能不一样。

作为对比,Gateway API 明确规定了如何合并规则与解决冲突:

  • Gateway 实现必须合并附加到同一 listener 的所有 HTTPRoute 的路由规则。
  • 冲突必须按照 API Design Guide: Conflicts 中规定的方式处理。例如,更具体的匹配规则会胜出。

默认后端(Default Backend) ​

Ingress 的默认后端会响应与该 Ingress 资源相关的、所有未被匹配的 HTTP 请求。Gateway API 并没有直接对应:你需要显式定义这样一条路由规则。例如:定义一条把路径前缀 / 的请求路由到对应"默认后端 Service"的规则。

选择要附加到的数据平面 ​

Ingress 资源必须通过 IngressClass 来指明使用哪个 Ingress 控制器。HTTPRoute 则必须通过 parentRef 指明要附加到哪个(或哪些)Gateway。

实现特有的 Ingress 特性(注解) ​

Ingress 注解用于配置实现特有的特性。因此,把它们转换为 Gateway API 时,需要同时参考 Ingress 控制器与 Gateway 实现的文档。

幸运的是,原先通过注解暴露的部分特性已经并入了 Gateway API(特别是 HTTPRoute):

  • 请求重定向(包括 TLS 重定向)
  • 请求/响应改写
  • 流量切分
  • 基于请求头、查询参数或方法的路由

不过,剩余的特性仍然大多是实现特有的。要转换它们,请查阅你所选用的 Gateway 实现文档,看它使用了哪种扩展点。

转换示例 ​

本节展示一个把 Ingress 资源转换为 Gateway API 资源的示例。

假设 ​

该示例包含以下假设:

  • 所有资源都属于同一命名空间。
  • 集群中存在对应的 IngressClass 资源 prod。
  • 它通过注解 example-ingress-controller.example.org/tls-redirect 支持 TLS 重定向。
  • 集群中存在对应的 GatewayClass 资源 prod(由 Gateway 实现提供)。

为简洁起见,示例中省略了被引用的 Secret、Service、IngressClass 和 GatewayClass 的具体内容。

Ingress 资源 ​

下面的 Ingress 定义了如下配置:

  • 使用注解 example-ingress-controller.example.org/tls-redirect,为 foo.example.com 和 bar.example.com 这两个主机名的 HTTP 请求配置 TLS 重定向。
  • 使用 Secret example-com 中的 TLS 证书与私钥,对 foo.example.com 和 bar.example.com 这两个主机名进行 TLS 终止。
  • 把 foo.example.com 主机名、URI 前缀为 /orders 的 HTTPS 请求路由到 foo-orders-app Service。
  • 把 foo.example.com 主机名、其他 URI 前缀的 HTTPS 请求路由到 foo-app Service。
  • 把 bar.example.com 主机名、任意 URI 的 HTTPS 请求路由到 bar-app Service。
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    example-ingress-controller.example.org/tls-redirect: "True"
spec:
  ingressClassName: prod
  tls:
  - hosts:
    - foo.example.com
    - bar.example.com
    secretName: example-com
  rules:
  - host: foo.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: foo-app
            port:
              number: 80
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: foo-orders-app
            port:
              number: 80
  - host: bar.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: bar-app
            port:
              number: 80

接下来三小节把这个 Ingress 转换为 Gateway API 资源。

转换步骤 1 — 定义 Gateway ​

下面的 Gateway 资源:

  • 属于我们的 GatewayClass prod;
  • 供给负载均衡基础设施(具体行为取决于 Gateway 实现);
  • 暴露三个 listener:
    • http listener,80 端口,HTTP 协议;
    • https listener,443 端口,HTTPS 协议,使用 example-com Secret(与 Ingress 中所用的相同)进行 TLS 终止;
    • https-default-tls-mode listener,8443 端口,HTTPS 协议,使用 foo-com Secret(演示默认 TLS 模式)。

同时请注意,两个 listener 都允许来自同一命名空间的所有 HTTPRoute(这是默认行为),并把 HTTPRoute 的 hostname 限制在 example.com 子域(允许 foo.example.com,但不允许 foo.kubernetes.io)。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: prod
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    hostname: "*.example.com"
  - name: https
    port: 443
    protocol: HTTPS
    hostname: "*.example.com"
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: example-com
  - name: https-default-tls-mode
    port: 8443
    protocol: HTTPS
    hostname: "*.foo.com"
    tls:
      certificateRefs:
      - kind: Secret
        name: foo-com

转换步骤 2 — 定义 HTTPRoutes ​

Ingress 被拆分为两条 HTTPRoute——一条对应 foo.example.com,另一条对应 bar.example.com 主机名。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: foo
spec:
  parentRefs:
  - name: example-gateway
    sectionName: https
  hostnames:
  - foo.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: foo-app
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /orders
    backendRefs:
    - name: foo-orders-app
      port: 80
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bar
spec:
  parentRefs:
  - name: example-gateway
    sectionName: https
  hostnames:
  - bar.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: bar-app
      port: 80

这两条 HTTPRoute 都:

  • 附加到上面 Gateway 的 https listener;
  • 与对应主机名下 Ingress 的路由规则保持一致。

步骤 3 — 配置 TLS 重定向 ​

下面这条 HTTPRoute 完成了 Ingress 通过注解配置的 TLS 重定向功能。它:

  • 附加到我们 Gateway 的 http listener;
  • 对主机名为 foo.example.com 或 bar.example.com 的任意 HTTP 请求发起 TLS 重定向。
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tls-redirect
spec:
  parentRefs:
  - name: example-gateway
    sectionName: http
  hostnames:
  - foo.example.com
  - bar.example.com
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        port: 443

自动转换 Ingress ​

Ingress to Gateway 项目帮助你把 Ingress 资源自动转换为 Gateway API 资源(特别是 HTTPRoute)。转换结果必须经过测试与验证。

基于 MIT 协议发布