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-managerExternalDNS 等多个云原生项目也集成了 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。

HTTPRoutehostnames 必须与 Gateway listenerhostname 相匹配。否则,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.combar.example.com 这两个主机名的 HTTP 请求配置 TLS 重定向
  • 使用 Secret example-com 中的 TLS 证书与私钥,对 foo.example.combar.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.combar.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 协议发布