客座文章作者:Gianluca Arbezzano,Equinix Metal 软件工程师,CNCF 大使;Alex Palesandro,都灵理工学院研究助理
Kubernetes 集群在组织内部的数量和规模都在增长。这种扩散是由各种原因造成的:可伸缩性问题、地理限制、多提供者策略等等。不幸的是,现有的多集群方法在 pod 放置、集群设置和与新 API 的兼容性方面有很大的局限性。此外,它们需要大量的手动配置。
在第一次 CNCF 都灵 Meetup 上,Alex 和 Mattia 讨论了多集群管理问题,强调了当前方法的局限性。他们讨论了克服当前限制的可能的技术选择,并提出了Liqo[1]中可能的实现,Liqo 是一个通过透明地聚合多个现有集群来动态创建“大集群”的项目。在讨论的最后,他们展示了 Liqo 在云爆发(cloud-bursting)场景中的演示。
Kubernetes 集群在数据中心中非常普遍,不同的区域已经成为现实。在容器化“革命”之后,Kubernetes 近年来已经成为事实上的基础设施管理标准。一方面,K8s 的普遍性是建立在云之上的。越来越多的提供者正在构建和交付作为服务的托管集群。另一方面,K8s 在本地安装(on-premise)也很受欢迎,Kubernetes 丰富的生态系统可以减少与公共云的“目录(catalog)”距离。此外,边缘设置也变得越来越流行:越来越多的项目专注于将 Kubernetes 引入轻量级和地理稀疏的基础设施。
尽管增加了所有的复杂性,但普遍存在的多集群拓扑引入了新的令人兴奋的潜力。这种潜力超越了目前所探索的通过多个集群进行的简单静态应用程序编排。事实上,多集群拓扑对于跨不同位置编排应用程序和统一对基础设施的访问非常有用。其中,这引入了一种令人兴奋的可能性,可以透明而快速地将应用程序从一个集群迁移到另一个集群。在处理集群灾难或关键基础设施干预、扩展或布局优化时,移动工作负载是可行的。
多集群拓扑主要引入了两类挑战:
许多项目都解决了多集群问题;在这里,我们总结了最常见的方法。
官方的 Kubernetes Cluster Federation(又名KubeFed[2])就是这种方法的一个例子,它“允许你从一个托管集群中的一组 API 协调多个 Kubernetes 集群的配置”。为此,KubeFed 用一种新的语义扩展了传统的 Kubernetes API,该语义表示应该为特定的部署选择哪些集群(通过“覆盖”和“集群选择器”)。
GitOps 是一个建立良好的框架来编排 CI/CD 工作流程。其基本思想是使用 git 仓库作为应用程序部署的单一数据源,并更新集群的相应对象。面对多集群拓扑结构,GitOps 可以代表一个基本的多集群控制平面。我们可以举几个 GitOps 工具例子,如FluxCD[3]、Fleet[4]和ArgoCD[5]。
在这样的场景中,应用程序使用合适集群的正确值进行模板化,然后部署到目标集群上。这种方法结合适当的网络互连工具,允许你获得多集群编排,而无需处理额外 API 的复杂性。
然而,GitOps 方法缺乏跨多集群拓扑的动态 pod 放置。它们不支持任何主动灾难恢复策略或跨集群爆发。特别是,不可能跨集群自动迁移工作负载以响应意外故障或快速处理不可阻止的负载峰值。
Virtual Kubelet(VK)[6]是一个“Kubernetes Kubelet[7]实现,它伪装成 Kubelet,将 Kubernetes 连接到其他 API”。初始的 VK 实现将远程服务建模为集群的节点,从而在 Kubernetes 集群中引入无服务器计算。后来,VK 在多集群上下文中变得流行起来:VK 提供者可以将远程集群映射到本地集群节点。包括Admiralty[8]、Tensile-kube[9]和 Liqo 在内的几个项目都采用了这种方法。
与专用 API 服务器相比,这种方法有几个优点。首先,它引入了多集群,不需要额外的 API,而且它对应用程序透明。其次,它灵活地将远程集群的资源集成到调度器的可用性中:用户可以以与本地 pod 相同的方式调度远程集群 pod。第三,它使分散治理成为可能。更准确地说,VK 可能不需要远程集群上的特权访问来调度 pod 和其他支持多所有权的 K8s 对象。
网络互连是多集群拓扑的第二个重要方面。Pod 应该能够与其他集群和服务上的 Pod 无缝通信。集群间连接性可以通过 CNI(负责集群连接性的组件)的扩展,或专用工具提供。
互联工具的关键设计选择主要涉及三个方面:(1)不同集群配置的互操作性;(2)其他集群使用的网络参数的兼容性;(3)如何处理所有集群暴露的服务。
CiliumMesh[10]是一个 CNI 实现多集群互联的例子。更准确地说,CiliumMesh 扩展了流行的 Cilium CNI 的能力,以“联合”不同集群上的多个 Cilium 实例(ClusterMesh)。Cilium 支持通过隧道或直接路由跨多个 Kubernetes 组的 Pod IP 路由,而不需要任何网关或代理。此外,它还通过标准的 Kubernetes 服务和 coredns 来促进透明的服务发现。
像 CiliumMesh 这样的方法的主要缺点是严格依赖给定的 CNI,即 Cilium。Cilium 必须在两组集群中采用。此外,Cilium 在 pod CIDR 跨集群特性方面有一些关键的要求。
Submariner[11]支持在不同 Kubernetes 集群中的 Pod 和服务之间直接联网,可以是本地的,也可以是云端的。Submariner 是完全开源的,设计成网络插件(CNI)无感的。Submariner 有一个基于代理的集中式架构,该代理收集关于集群配置的信息并发回参数以供使用。
Submariner 不支持将端点分布在多个集群(多集群服务)中的服务。它提供了一种更直接的发现远程服务的机制,使所有后端 pod 都位于正确的位置。
Skupper[12]是一个七层业务的多集群互联服务。Skupper 通过定义一个特别的虚拟网络基底,实现了 Kubernetes 集群之间的安全通信。与 Submariner 和 Cilium 不同,Skupper 并不引入集群范围内的互连,而是只针对特定的命名空间集。Skupper 在 Skupper 网络中暴露的命名空间中实现了多集群服务。当一个服务被暴露时,Skupper 会创建特定的端点,使它们在整个集群上可用。
服务网格框架是专用的基础架构层,用于简化基于微服务的应用程序的管理和配置。服务网格引入了一个边车(sidecar)容器作为代理,以提供多种功能(例如,使用相互 TLS 的安全连接、断路、canary 部署)。
一些最流行的服务网格架构(ISTIO[13]、Linkerd[14])具有多集群支持,以支持多集群的微服务应用程序。不同集群之间的互连使用一个专用代理将流量从一个集群的网格路由到另一个。类似地,Istio 和 Linkerd 可以跨集群创建一个临时的相互 TLS 隧道,并提供原语来跨集群暴露服务,从而支持诸如跨集群流量分割等特性。
一般来说,服务网格框架中的多集群支持提供了广泛的特性。但是,它们需要许多步骤和几个新的特定 API 来配置以设置拓扑。
上述方法的类别有几个局限性。首先,对于其中许多(Kubefed 和 GitOps),pod 的放置是静态的,不可能进行细粒度的集群优化。其次,这些项目要么处理网络平面,要么处理控制平面:这需要第三方工具来处理互连。总的来说,这种分离的方法排除了从现有拓扑中快速插入或删除集群的情况。例如,我们将在后面讨论,Liqo 集成方法支持实现与 CNI 无感的多集群服务支持,其中服务端点使用正确的 IP 地址添加到 K8s 中(即考虑到 natting 规则和网络拓扑)。
Liqo 背后的思想是使多集群拓扑成为集群管理员的单步操作。这是通过结合一种基于 Virtual Kubelet 的方法来处理多集群控制平面和一个与 CNI/IP 配置无感的专用网络结构来获得的。简而言之,Liqo 提供了对集群的统一访问,防止 Kubernetes 用户提前了解多集群拓扑结构。Kubernetes 管理员可以通过添加或删除集群来更改拓扑,而不会影响他们的用户,也可能不会影响正在运行的工作负载。
一方面,动态意味着可以在运行过程中添加和删除集群“同行(peering)”到拓扑上。另一方面,Liqo 通过实现 pod 卸载和依赖于专用 Virtual Kubelet 提供商的多集群服务,为应用程序提供了透明度。
Liqo 与其他项目的主要区别见表 1 和表 2。
表 1 – Comparison of Control-Plane Multi-cluster projects
Criteria | Liqo | Admiralty | Tensile-Kube | Kubefed | ArgoCD | Fleet | FluxCD |
Seamless Scheduling | Yes | Yes | Yes | No | No | No | No |
Support for Decentralized Governance | Yes | Yes | Yes | No | Yes | Yes | Yes |
No Need for application extra APIs | Yes | Yes | Yes | No | No | No | No |
Dynamic Cluster Discovery | Yes | No | No | No, using Kubefed CLI | No | No | No |
表 2 – Comparison of Network Interconnection projects
Criteria | Liqo | Cilium ClusterMesh | Submariner | Skupper | Istio Multi-Cluster | Linkerd Multi-cluster |
Architecture | Overlay Network and Gateway | Node to Node traffic | Overlay Network and Gateway | L7 Virtual Network | Gateway-based | Gateway-based |
Interconnection Set-Up | Peer-To-Peer, Automatic | Manual | Broker-based, Manual | Manual | Manual | Manual |
Secure Tunnel Technology | Wireguard | No | IPSec (Strongswan, Libreswan), Wireguard | TLS | TLS | TLS |
CNI Agnostic | Yes | No | Yes | Yes | Yes | Yes |
Multi-cluster Services (“East-West”) | Yes | Yes | Limited | Yes | Yes, with traffic management | Yes, with traffic splitting |
Seamless Cluster Extension | Yes | Yes | Yes | No | No | No |
Seamless Support for Overlapped IPs | Yes | No | No, it relies on global IPs networking | Yes | Yes | Yes |
Support for more than 2 clusters | In Progress | Yes | Yes | Yes | Yes | Yes |
Liqo 实现了一种机制,只需一步就可以发现一个集群,并将其与另一个集群匹配(peer)。发现依赖于 DNS SRV 记录(如 SIP)、LAN mDNS 和作为最后手段的手动插入。当发现一个新的集群时,将在集群之间建立一个管理互连,称为 peering,模拟涉及不同互联网运营商之间互连的类似过程。Peering 进程依赖于 P2P 协议,该协议允许在两个集群之间交换参数,以定义安全的网络配置。
Liqo 组网的基本原则是保持单集群组网的基本功能。特别是,主要的重点是保持直接的 pod 到 pod 的流量,从用户的角度支持透明的扩展。作为服务端点发现的 pod 可以到达,即使它们在另一个集群上,或者它们的地址与“主”集群 pod 地址空间发生冲突。
在底层,通过覆盖网络建立集群互联,将流量路由到远程集群。Liqo 利用了一个“网关”pod,它使用 Wireguard 连接到远程节点。这种架构避免了要求(如在 CiliumMesh 中)让参与集群的所有节点完全可以从另一个集群到达。此外,Liqo 还处理可能重叠的 pod IP 地址,通过双 nat 进行处理。
Liqo 主要独立于连接集群或兼容 POD CIDR 的 CNI。CNI 可以独立选择,Liqo 还支持被管理的集群(即 AKS、GKE)及其网络架构。
在进行匹配(peering)检查之后,一个新节点被添加到集群中。这个虚拟节点将描述另一个可用于调度的集群的 CPU 和内存数量。普通的 Kubernetes 调度器可以直接将 pod 分配给这个创建的节点。匹配的过程定义了节点的大小,实际上引入了去中心化治理的可能性。集群管理员可以调整向其他集群暴露的资源数量。
使用 Liqo,对面向用户的 Kubernetes 没有中断。例如,当用户在 liq 标记的命名空间上部署应用程序时,命名空间内容反映在另一个集群上的孪生命名空间中。更准确地说,在“孪生(twin)”命名空间内,大部分 K8s 对象复制到远程命名空间上。这使得 pod 可以透明地远程执行并访问其配置对象。
这对于服务反射尤其有趣,它实现了“东西”的多集群服务。Pod 可以访问多集群拓扑中的任何位置的服务。在幕后,服务端点由 Liqo VK 操纵,精心设计还考虑 NAT 转换。
最后,Liqo pod 卸载是容忍裂脑的。当 pod 被卸载到远程集群时,它们被包装在 replicaset 对象中。这样,即使与原始集群的连接丢失,卸载的 pod 状态也会继续在远程集群上正确地协调。
Liqo 最近发布了它的第二个主要版本——0.2。下一个版本(v0.3,预计 2021 年 7 月中旬)计划的特性如下:
随着集群数量的增加,多集群拓扑将开始变得越来越流行。
Liqo 提出了一种有趣的方法来简化这个问题,它提供了一种创建虚拟集群抽象的方法,该抽象为集群提供统一和一致的视图,从而简化了多集群拓扑的创建和管理。
[1]
Liqo: https://liqo.io/
[2]
KubeFed: https://github.com/kubernetes-sigs/kubefed
[3]
FluxCD: https://fluxcd.io/
[4]
Fleet: https://rancher.com/docs/rancher/v2.x/en/deploy-across-clusters/fleet/
[5]
ArgoCD: https://argoproj.github.io/argo-cd/
[6]
Virtual Kubelet(VK): https://virtual-kubelet.io/
[7]
Kubernetes Kubelet: https://kubernetes.io/docs/reference/generated/kubelet/
[8]
Admiralty: https://github.com/admiraltyio/admiralty/blob/master/README.md#readme
[9]
Tensile-kube: https://github.com/virtual-kubelet/tensile-kube/blob/master/README.md#readme
[10]
CiliumMesh: https://docs.cilium.io/en/v1.9/concepts/clustermesh/
[11]
Submariner: https://submariner.io/
[12]
Skupper: https://skupper.io/
[13]
ISTIO: https://istio.io/
[14]
Linkerd: https://linkerd.io/