在本文中,我们介绍了可用于 从一处迁移 入口控制器 现有 Kubernetes 到另一个。
什么是入口控制器?
和 入口 是一个流行的 Kubernetes API 资源,用于 将传入的 HTTP(S) 请求路由到相应的后端 (pod)。 集群用户可以创建资源 入口 定义路由规则,例如:“将请求转发到 www.example.com/api 到与服务 XYZ 关联的 Pod”。 这些资源依赖于一个或多个 入口 实现流量管理、路由和负载均衡。
入口控制器是 本质上是一个 HTTP 负载均衡器 (也叫 负载均衡器第 7 层)通过 Kubernetes API 配置。 当您向入口控制器管理的域发送请求时,后者会接收该请求,对其进行分析以执行可能的预处理(过滤、添加标头等),确定其目的地(即要发送到哪个 pod)将其发送给),将其转发给它,最后将响应发送回给您。
请注意,用户和 Kubernetes 文档在谈论“入口”时有时会遇到一些困惑,“入口”可以根据上下文指定资源 入口 或一个 入口控制器。
为什么要从一个入口控制器迁移到另一个入口控制器?
不幸的是,原始 API 是相对有限的。 它只允许根据主机名和 URL 路径来路由请求,这在现代网络世界中通常是不够的。
例如,我们经常需要 指定一个 重定向 HTTP 确保用户通过安全的 TLS 连接(以 URL 方案 https:// 开头)访问我们的网站和应用程序。 我们可能还想要 使能够 HSTS 为了提高安全性, 实施部署 金丝雀/蓝绿, 或者 通过以下方式促进身份验证 认证2。
许多入口控制器决定实施自己的解决方案来填补这些空白。 但由于这些“高级”功能并不是原始入口规范的一部分, 不同入口控制器的实施质量和细节各不相同。 这意味着,尽管几乎所有入口控制器都实现了入口规范,但它们提供了各种扩展,并且当这些扩展对我们应用程序的可用性或性能至关重要时, 入口控制器的选择成为我们 Kubernetes 集群解决方案的支柱。 最初旨在可互换,入口控制器根本不再可互换!
从长远来看,某些设计选择可能会受到质疑,并且更改它们可能需要复杂且成本高昂的迁移。 然而,在本文中我们将看到 入口控制器的选择不必是最终的。 有 从一个入口控制器到另一个入口控制器的迁移解决方案 如果最初的选择不再是最佳选择或者我们的要求发生了变化。
但是,如果您正在决定或质疑入口控制器的选择,请阅读来自以下网站的这份非常详尽且经常更新的文档: Kubernetes 入口控制器比较 可能对你有用。
入口控制器的类型
在讨论迁移场景之前,我们可以先对迁移场景进行分类 入口控制器 根据以下类别:
类型 |
描述 |
云入口 |
入口控制器由云提供商实现,通常在 Kubernetes 集群外部运行。 由于实现细节是特定于供应商的,因此仔细阅读文档以确保所有内容都配置正确非常重要。 例如,在某些场景中,某些入口控制器可能需要“nodePort”服务,这通常会导致性能不佳。 |
通过 LoadBalancer 类型的服务公开的内部 Ingress |
入口控制器在 Kubernetes 集群内部工作,可通过 LoadBalancer 类型服务进行访问,该服务本身由提供 4 级 (L4) 负载均衡器的 Cloud Load Balancer 实现。 在这种情况下,HTTP 请求遵循以下路径: 客户端 → 云负载均衡器 → Pod 入口控制器 → Pod 应用程序。 这是一种非常流行的部署方法,但对于大多数云负载均衡器,客户端的源 IP 地址信息都会丢失(请求似乎来自负载均衡器)。 为了保留客户端的 IP 地址,在某些情况下可以使用“ 外部流量策略 : 当地的 ”。 另一种选择是使用 代理协议 云负载均衡器和入口 Pod 之间 – 当它们都支持此协议时。 |
通过 hostPort 进行 Ingress Interne 暴露 |
入口控制器在 Kubernetes 集群内部运行,并通过“hostPort”(通常是端口 80 和 443)公开。 这实质上是将这些端口从 pod 运行的节点映射到 pod 本身。 这自然会保留源 IP 地址。 但是,对于高可用性场景,Pod 必须部署在多个节点上,并且这些节点的公共(外部)IP 地址必须全部更新到入口控制器的 DNS 记录中。 这通常是通过 DaemonSet(以及可选的 nodeSelector)来实现的。 |
通过主机网络进行 Ingress Interne 暴露 |
入口控制器在 Kubernetes 集群内部运行,可以直接访问其运行的节点的网络接口。 它类似于“hostPort”场景,但由于 Ingress Controller 可以完全访问节点的网络堆栈,因此它甚至可以利用 IPv6 或 UDP (HTTP3)。 |
Ingress 控制器迁移场景
现在我们已经概述了在 Kubernetes 上部署入口控制器的主要方式,让我们来谈谈 迁移场景。
这些场景主要取决于我们的入口控制器的部署方式。 它们是通用指南,应谨慎对待。 在迁移到生产环境之前,务必在临时环境中尝试迁移步骤,这一点很重要。
A) DNS 切换
在这种情况下,双方 Ingress Controller 有自己的外部 IP 地址,这意味着迁移主要是通过更新DNS记录来完成的。
场景的适用性
的 |
有 |
云入口 | 通过 LoadBalancer 服务暴露的内部 Ingress |
通过 LoadBalancer 服务暴露的内部 Ingress | 云入口 |
通过 LoadBalancer 服务暴露的内部 Ingress | 通过 LoadBalancer 服务暴露的另一个内部入口 |
注意:上表中没有“云入口到云入口”场景,因为这种情况极其罕见(云提供商至少有两个单独的入口控制器的情况)。 如果您处于这种情况,云提供商可能会为您提供专门的迁移指南。
停机时间
没有服务中断。
描述
为了避免停机,最好的选择是 并行运行两个入口控制器,检查新入口是否一切正常,最后 依次切换 DNS 以最大程度地降低风险。
入口控制器通常依赖于资源的“入口”类 入口 以确定他们是否应该管理该资源。 从一个入口控制器迁移到另一个入口控制器时,您可以 创建重复的入口资源(对于两个入口控制器),或配置至少一个入口控制器来管理 全部 入口资源,忽略他们的入口类。
请注意,第二个选项可能会导致两个入口控制器之间发生冲突,因为它们可能会竞争更新入口资源的“status.loadbalancer”字段以反映其负载均衡器的外部 IP 地址。 虽然这本身是无害的,但如果您使用依赖于该字段的工具(例如,ExternalDNS),则可能会导致问题。
由于 Kubernetes 中不明确支持同时使用两个入口控制器管理给定的入口资源,因此如果您采用此方法,则应在临时环境中对其进行彻底测试,并确保它不会在任何入口控制器中触发错误。
如果这些测试揭示了问题(例如,如果两个入口控制器正在竞争同一个输入对象),请返回到原始计划并为每个入口控制器保留一个入口类,然后在准备好时进行切换。
更新 DNS 记录时,建议在迁移前将其 TTL 降低到较低值(例如 30 到 300 秒),以减轻仍指向旧(且可能无效!)IP 的过时 DNS 记录的影响地址; 并在迁移完成后将 TTL 恢复为其初始值。
例子
如果您部署 NGINX Ingress 及其 Helm 图表,您可以添加以下值:
--set controller.watchIngressWithoutClass=true
如果您部署 HAProxy Kubernetes 入口控制器 及其 Helm 图表,对应的值为:
--set "controller.extraArgs[0]=--empty-ingress-class”
B) LoadBalancer IP 地址的重用
场景的适用性
的 | 有 |
通过 LoadBalancer 服务公开的内部入口 | 通过 LoadBalancer 服务公开的另一个内部入口 |
停机时间
几秒钟(链接到云控制器管理器)。
描述
从概念上讲,在这种情况下我们 让我们将一个 LoadBalancer 服务的公共 IP 地址重新分配给另一个 LoadBalancer 服务。 这是通过在新服务中设置“spec.loadBalancerIP”字段来实现的。
如果您想使用此场景,则需要了解一些重要的细节。
首先,该功能仅在某些云控制器管理器上支持; 因此您应该检查文档在您的特定云环境中是否可用。
那么,这可能需要“锁定”相应的IP地址,使其不被释放并返回到云提供商池。
最后,“spec.loadBalancerIP”字段在 Kubernetes 1.24 中已被弃用,取而代之的是云提供商特定的注释。 一些提供程序仍然实现该字段,而其他提供程序则需要使用注释。 您再次需要检查文档(例如 对于谷歌云, 或者 倾注微软Azure)。
这是 此迁移场景的不同阶段 :
- 使用 LoadBalancer 类型服务部署新的入口控制器
- 在这个LoadBalancer类型的新服务中,将“spec.loadBalancerIP”(或1.24或更高版本中的相应注释)设置为旧入口控制器(仍在运行)的LoadBalancer类型服务的IP地址; 负载均衡器的此外部 IP 地址目前可能显示为待处理
- 可能的话,备份 LoadBalancer 类型的旧服务(使用
kubectl get service -o yaml …
) - 验证新的入口控制器是否正常工作(例如,使用
kubectl port-forward
或任何其他技术) - 准备好后,删除 LoadBalancer Service 类型的旧服务
- 云控制器管理器会自动将旧负载均衡器的 IP 地址重新分配给新负载均衡器。
例子
界定 负载均衡器IP 对于 l’ingress Traefik :
service:
spec:
loadbalancerIP:
C) 节点推出
场景的适用性
的 | 有 |
通过 HostPort 进行入口暴露 | 通过 HostPort 进行入口暴露 |
通过 HostNetwork 进行 Ingress 暴露 | 通过 HostPort 进行入口暴露 |
通过 HostPort 进行入口暴露 | 通过 HostNetwork 进行 Ingress 暴露 |
通过 HostNetwork 进行 Ingress 暴露 | 通过 HostNetwork 进行 Ingress 暴露 |
停机时间
- 部署到不同节点时不会出现停机(需要额外的步骤,例如使用 DNS)
- 在同一组节点上部署时停机时间短(启动入口控制器 Pod 所需的时间;通常在几秒到一分钟之间)
描述
在这种情况下, 入口控制器在一组节点上工作。 这通常是在 使用守护进程集在整个集群(对于小型集群)或指定的节点子集(使用节点选择器)上运行入口控制器。 HTTP 和 HTTPS 流量通过端口 80 和 443 发送到这些节点。
如果当前入口控制器部署在节点子集上,可以通过在另一组节点上部署新入口来避免服务中断。 然后可以在不中断当前入口的情况下彻底测试新入口的行为。 一旦操作被验证,流量可以通过更新 DNS 记录切换到新的入口:
- 为新节点添加记录
- 从旧节点中删除那些
- 一旦流量完全迁移到新节点,停止旧的入口。
如果集群中所有节点都部署了当前的入口控制器,所使用的方法不同。 要测试新入口,请将其部署在不同的端口号(例如 8080 和 8443)上。 一旦新入口正常工作,就可以进行迁移。 以下步骤略有不同,具体取决于我们使用 HostNetwork 还是 HostPort。
使用 HostPort 时,Kubernetes 负责将连接从主机端口(例如 80 和 443)转发到 Pod。 由于端口在 pod 清单中明确列出,Kubernetes“知道”这些端口是在主机上分配的。 因此,它将防止两个 Pod 使用相同的端口:第一个 Pod 将被调度并正常启动,而具有相同端口的第二个 Pod 将保持“待处理”状态,因为调度程序能够识别所请求的主机端口资源是不可用。不可用。 我们可以依靠这一行为来实现从旧入口到新入口的平滑迁移,如下所示:
- 为新的入口控制器创建守护进程集(其 Pod 将被创建,但仍保持“待处理”状态)
- 使用标志“–cascade=orphan”从旧入口控制器中删除守护进程集(以便其 Pod 继续工作)
- 一一删除旧的 Pod,验证新的 Pod 是否正确启动
如果出现问题,这种谨慎的方法允许您通过重新创建其守护进程集来快速恢复到旧的入口控制器。
使用 HostNetwork 时,入口控制器 Pod 使用它们所运行的节点的默认网络命名空间。 也就是说,入口控制器监听HostNetwork中的TCP/80端口时,直接是主机上的TCP/80端口; 因此,无需对 IP 数据包进行额外处理。 这使得它能够提供本机的、因此最佳的性能。 这种模式的缺点是 Kubernetes 不再控制端口的分配和预留,并且无法阻止两个 pod 尝试连接到同一端口。 如果两个不同的入口控制器尝试在同一主机上操作,这将导致冲突:第一个会成功,而第二个会收到“地址已在使用中”错误消息。
部署需要仔细协调, 停止旧入口控制器中的每个 Pod 并按顺序创建其替代品。
最后一点:HostNetwork 和 HostPort 方法之间的迁移是可能的,但也需要仔细协调,因为 Kubernetes 再次无法识别使用 HostNetwork 的 Pod 使用的端口。
例子
配置 Kong HostPort:
--set proxy.http.hostPort=
8080 --set proxy.tls.hostPort=8443
结论
在这篇文章中,我们列出了 从一个入口控制器迁移到另一个入口控制器时可能应用的最常见场景。
实际上,如果您在云中运行 Kubernetes,您更有可能发现自己处于前两种情况之一。 第三种情况对于较小的本地 Kubernetes 集群来说更为常见。
在所有情况下, 入口控制器是无状态组件,因此它们可以“即时”更改,对服务的影响最小(如果有)。 总而言之,如果您当前的入口控制器不能满足您的所有要求,则可以不积累技术债务:您可以安全地迁移到新的、更合适的入口控制器!
不要错过我们的下一篇文章 开发运营 等 云原生! 跟随 艾尼克斯 在 推特!