从 Ingress 迁移
原文:https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/
Gateway API 是 Ingress API 的继任者。本指南提供从任何 Ingress 实现迁移到 Gateway API 的总体概览。内容聚焦于 Ingress 与 Gateway API 之间的核心概念、关键差异和功能映射,并给出一份手工转换示例。
本指南会帮助你完成转换。它会:
- 解释你为何要切换到 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-appService。 - 把
foo.example.com主机名、其他 URI 前缀的 HTTPS 请求路由到foo-appService。 - 把
bar.example.com主机名、任意 URI 的 HTTPS 请求路由到bar-appService。
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 资源:
- 属于我们的
GatewayClassprod; - 供给负载均衡基础设施(具体行为取决于 Gateway 实现);
- 暴露三个 listener:
httplistener,80 端口,HTTP 协议;httpslistener,443 端口,HTTPS 协议,使用example-comSecret(与 Ingress 中所用的相同)进行 TLS 终止;https-default-tls-modelistener,8443 端口,HTTPS 协议,使用foo-comSecret(演示默认 TLS 模式)。
同时请注意,两个 listener 都允许来自同一命名空间的所有 HTTPRoute(这是默认行为),并把 HTTPRoute 的 hostname 限制在 example.com 子域(允许 foo.example.com,但不允许 foo.kubernetes.io)。
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 主机名。
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: 80apiVersion: 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 的
httpslistener; - 与对应主机名下 Ingress 的路由规则保持一致。
步骤 3 — 配置 TLS 重定向
下面这条 HTTPRoute 完成了 Ingress 通过注解配置的 TLS 重定向功能。它:
- 附加到我们 Gateway 的
httplistener; - 对主机名为
foo.example.com或bar.example.com的任意 HTTP 请求发起 TLS 重定向。
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)。转换结果必须经过测试与验证。