文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

浅析 Kubernetes 多集群调度方案

2024-12-01 18:38

关注

Kubernetes 是一个容器编排平台,用于调度、部署和管理容器化应用。并且经过几年的发展,k8s 已经成为事实上的容器编排平台标准。集群是 k8s 架构的构建块(building block)。集群由多个工作节点(物理机或者虚拟机)组成,提供一个可供容器运行的资源池。一个集群拥有:

每个集群都是独立的系统,可以部署在公司的自建机房,也可以部署在云厂商的一个可用区。k8s 负责管理集群的可用资源:调度器将容器调度到适当的机器、kubelet 负责 pod/ 容器的生命周期管理。这些都是大家很熟悉的概念了。但是 k8s 的作用范围是集群内,一个集群内的控制平面无法感知另一个集群的资源余量和服务状态。当多集群的应用场景出现时,我们怎么处理多个集群的调度呢。

为什么要有多集群调度?

通常来说,一个集群的大小需要预估业务的资源总量。当资源不够时,可以通过增加机器数量来进行集群扩容。但是集群规模也不是无限上升的。当节点 /pod 的数量越多,对控制平台的组件的压力就越大,进而影响集群整体稳定性。

当然,使用多集群调度肯定会增加整体架构的复杂度,集群之间的状态同步也会增加控制面的额外开销。所以,多集群的主要攻克的难点就是跨集群的信息同步和跨集群网络连通方式。跨集群网络连通方式一般的处理方式就是确保不同机房的网络相互可达,这也是最简单的方式。

而我比较干兴趣的是跨集群的信息同步。多集群的服务实例调度,需要保证在多集群的资源同步的实时,将 pod 调度不同的集群中不会 pod pending 的情况。控制平面的跨集群同步主要有两类方式:

KubeFed[1]Liqo[2]都是开源项目,两者的主要区别如下:

场景

Kubefed

Liqo

Pod 调度

静态调度、动态调度只支持 Deployment/ReplicaSet

动态调度,但是还是会出现 pending 情况

控制平面

一套中心化管理组件

每个集群对等管理

集群发现

主动注册

动态发现和注册新集群

本文不会详细介绍这些项目在部署和网络管理的内容,重点分析两个项目(Kubefed、Liqo)的跨集群资源调度。

KubeFed

KubeFed 的目的是通过统一的 API 管理多个 k8s 集群,实现单一集群管理多个 k8s 集群的机制,并通过 CRD 的机制来扩展现有的 k8s 资源跨集群编排的能力。

KubeFed 将集群分为 host cluster,member cluster 两个角色:

被联邦管理的 k8s API 资源统称为 Federated Resources,例如 FederatedDeployments。开启跨集群调度也需要在 host cluster 上显式地对应用资源开启集群联邦管理,开启的方式是通过 ​​kubefedctl federate​​ 创建 FederatedTypeConfig。KubeFed 也支持联邦化 namespace,让 namespace 下面的资源都联邦化。通过 federation control plane 来下发资源到 member cluster。

kubefed-overview

KubeFed 概览

资源调度

那 KubeFed 怎么支持跨集群部署的呢?在开启资源的联邦化之后,Federated Resources 的 spec 分成 3 个基础配置 :

用户在部署服务时,可以在 spec 下定义部署的集群(placement)和集群指定参数(overrides)。比如服务需要在 cluster2 集群上增加副本数,修改 deployment 的 replicas,需要在 overrides 上填写“/spec/replicas”的修改。可以想到为了通用,overrides 的配置有一定复杂性。

spec:
template:
metadata:
labels:
app: nginx
spec:
replicas: 3
...
placement:
clusters:
- name: cluster2
- name: cluster1
overrides:
- clusterName: cluster2
clusterOverrides:
- path: "/spec/replicas"
value: 5
...

Federated  Resources 还支持通过另一个 CRD 来 ReplicaSchedulingPreference 配置资源类型级别的集群调度倾向。该方法通过指定资源类型在 member cluster 的最大 / 最小副本数实现了依据剩余可用资源的动态平衡。最终 controller 会将 preference 信息更新到 Federated Resources 的 overrides 上,从而重新分配实例。不过该功能还只支持 deployment/replicaset 资源。

可以看出在 KubeFed 的架构,还是区分了不同集群的配置和动态调度。

具体看看静态调度和动态调度。

静态调度

首先,FederatedTypeConfig 的 spec 里定义了 host cluster 中的 Federated Resources 和 member cluster 集群的所代表的资源:

spec 对应的 federatedType 是定义的联邦资源(由用户创建),而 targetType 实际上是真正的 k8s workload 资源, KubeFed 的 controller 可以通过 federatedType 的 placement 和 overrides 来控制各个集群里的对应的  targetType  的资源的分布。具体来说,负责下发 targetType 的 SyncController 会调用 dispatcher 生成 JSONPatch 并向 member cluster 创建底层资源。

kubefed-static-scheduling

KubeFed 静态调度

默认创建 Federated 资源时,可以在 spec 下定义部署的集群(placement)和集群指定参数(overrides),实现多集群的 pod 分配。但是这种调度是静态的。如果 overrides 设置的副本数超过集群剩余可用资源,那么新 pod 在集群里因为资源不够导致 pending。静态方式在大规模场景下无非是低效的,扩集群调度在极端情况下需要人工观测集群剩余资源来规划集群分布。但是很多服务是不需要感知集群信息的,他最在意的是还是服务实例能够正常启动,希望服务在不同集群的打散是一种动态被平台托管的。所以 KubeFed 引入了 ReplicaSchedulingPreference(RSP)的功能。

RSP 的实现依赖于一个新的 CRD——ReplicaSchedulingPreference 关键的几个配置项为:

例如,下面这个例子期望 cluster1 和 cluster2 以 2:3 的比例下发服务的副本。当集群资源充足时,cluster1 会分配 4 个 pod,cluster2 被分配 6 个实例。当集群 cluster2 资源不足时,rebalance 的设置允许将 cluster2 的副本挪到 cluster1。

spec:
targetKind: FederatedDeployment
totalReplicas: 10
rebalance: true
intersectWithClusterSelector: false
clusters:
cluster1:
weight: 2
cluster2:
weight: 3

下图描述了 KubeFed RSP 的工作流程,起作用的组件是 ReplicaScheduler。

kubefed-rsp-sched

KubeFed ReplicaSchedulingPreference workflow

ReplicaScheduler 首先会获取 PreferredClusters,将健康的集群的信息收集。然后获取当前服务副本的集群分布,会统计每个集群的 currentReplicasPerCluster、estimatedCapacity:

pod-unschedulable

ReplicaScheduler.Planner 依据上述信息(RSP 的 spec、currentReplicasPerCluster 和 estimatedCapacity),在可用集群中分配副本。Planner 的第一步会依据 ReplicaSchedulingPreference 中集群权重将可用集群排序,并划定每个集群的可分配上界和下界:

最终依据集群权重,将副本分配到各集群中。

ReplicaScheduler.Plugin 获得新的 overrides 信息将原 Federated  resources 的 spec 更新。之后的流程就是原有静态调度负责下发到集群。整个 ReplicaSchedulingPreference 能够动态地在多个集群分配 pod,并且包含了处理 Pending Pod 的情况。

但是局限在于只支持 Deployment/ReplicaSet 资源。

Liqo

与 KubeFed 相比,Liqo 有着 pod 无缝调度、去中心化治理等优势。

Liqo 将集群划分为 home cluster 和 foreign cluster。在每个集群都需要安装 liqo 的组件来管理多集群,这两类集群本质上没有区别。只是对于 home cluster 来说,其他的 foreign cluster 都是通过 Virtual Kubelet[3] 的方式映射成本集群节点。home cluster 将 foreign cluster 当作一个大的节点来使用。这样就能做到用户在 home  cluster 上创建资源时,能够调度到 foregin cluster 上。Virutal Kubelet 具体的内容可以看这篇文章《Virtual Kubelet[4]》。Virutal Kubelet 依据目的实现如下功能,就能在 k8s 集群内注册一个虚拟的节点。

自定义的 provider 必须提供以下功能:

  • 提供 pod、容器、资源的生命周期管理的功能
  • 符合 virtual kubelet 提供的 API
  • 不直接访问 k8s apiserver,定义获取数据的回调机制,例如 configmap、secrets

在集群注册方面,Liqo 支持动态发现集群(mDNS、LAN 两种方式)。在安装 Liqo 组件时,可配置集群通过何种方式发现和集群共享出去的资源百分比(默认 30%)。所以 Liqo 的多集群前提是集群之间已经网络可达。

Ligo 调度

在调度方面,因为 remote cluster 通过 virtual  kueblet 将该集群视为一个大节点,可以直接依赖本集群的 kube-scheduler 来调度。但是这里还是有个问题。当 remote  cluster 的资源碎片比较多时,大节点上报资源时会聚合成一个大块资源。导致大套餐的 pod 调度到 remote  cluster 会出现 pending。

Ligo 的工作流程如下图所示 . 当用户创建一个 deployment 时,默认调度器负责判断能否调度到 virtual node 上。之后这个服务的 pod 创建会被 virtual kubelet 接管。当 pod 被调度的 virtual node 上时,virtual  kubelet 会在 remote cluster 会对应的 replicaSet。使用 replicaSet 原因是 remote  cluster 上的 pod 被驱逐时,能够在集群上重建,而不是在 home cluster 重新调度。

liqo-pods-management

在了解多集群调度的细节之前,需要先弄清楚 virtual kubelet 的工作机制。我们知道 Kubelet 有个 SyncHandler, virtual  kubelet 也有 PodLifecycleHandler,处理 pod 被 k8s 创建、更新、删除的情况。例如,Liqo 的 virtual  kubelet 处理创建 pod 时,会先将 pod 的元数据里包含 home cluster 的信息转换成 foreign cluster  (比如 label 和 namespace),然后将 pod 包在 ReplicaSet 里通过 foreign Client 创建 ReplicaSet 资源。

上面介绍了一个 pod 在不同集群之间的映射。接下来从 foreign cluster 的角度发现 home cluster 的共享资源的具体流程。下属 Controller 和 CRD 都是由 Liqo 安装。

liqo-discovery

第一阶段:发现 foreign cluster 并上报可用资源

  1. DiscoveryController 是第一个集群注册的 controller,DiscoveryController 发现并创建 foreignCluster 资源:通过 WAN/LAN 发现远端集群,将 remote  cluster 的信息填入 foreignCluster.spec,之后的 Controller 通过 foreignCluster 来获取 remote  cluster 的信息。
  2. ForeignClusterController 监听 foreignCluster  CR,并维护 remote cluster 的 identity 信息。这些信息用来构建 virtual  kubelet,和 crdReplicator 使用。ForeignClusterController 通过 Authentication  Service 向远端的集群 ForeignAuthURL 验证 remote cluster 的身份信息,并将集群的证书存储在本地 secret。
  3. ForeignClusterController 在确认 foreign cluster 期望 outgoingPeering(即 home cluster 可以分享资源给 foreign cluster 使用),会创建  resourceRequest CR(不包含具体资源,只有集群元数据  authURL,用作后续资源请求的处理)。ResourceRequestController 监听 resourceRequest  CR,首先确保 foreignCluster 的 foreignCluster/tenant 资源存在;如果不存在则创建 CR,确保 ForeignAuthURL 是 resourceRequest.Spec.AuthURL。
  4. ResourceRequestController 负责监控本地资源,将需要更新共享资源配额的 remote cluster  id 压入 Broadcaster 组件的队列里。将集群 Broadcaster 组件接着调用 OfferUpdater.Push 做资源同步。OfferUpdater 负责组装 resourceOffer 里。resourceOffer 的 spec 保存集群的可共享资源,供远端的 virtual kubelet 查询。
  5. 并且 ResourceRequestController 还会监听本地 node/pod 事件,维护集群资源缓存(将 home cluster 全局可用资源,和 remote  cluster 占用资源分开)。当达到更新阈值(默认 80%),也会主动调用 OfferUpdate.Push 更新可用资源。当创建 pod 时,集群资源减去 pod 资源;当 pod 有 remoteClusterId 标签(vk 添加)时,会累加共享的 remote 集群的资源。做到区分本集群和 remote pod,当集群资源-pod 变化资源,会触发更新。
  6. 最终 ResourceRequestController 的 OfferUpdater 按序处理 5、6 步 pushed 的 queue 里集群 id,获取 home cluster 集群资源并更新 home 集群的 ResourceOffer  资源上限(offer.Spec.ResourceQuota.Hard) 。计算公式:(本集群可用资源量 + remote  cluster 的 pod 资源 )* ResourceSharingPercentage(依据配置共享给远端所有集群的资源)。

第二阶段:virtual kubelet 监听 home cluster 的资源变化

  1. 从 foreign cluster 的角度,也会发现 home cluster 并创建相应的 foreign cluster。virtual  kubelet 在 foreign cluster 注册时,初始化 virtual-kubelet  provider。在初始化的时候通过 foreignClusterID 拿到 home cluster 的 kubeClient  Config(上一阶段集群注册时生成的 secret)。
  2. LiqoNodeProvider 监听 resourceOffer 资源(通过 foreignClusterID 获得自己的可用资源量)。从 offer 里的 ResourceQuota 中获的 node 的资源的 Capacity 和 Allocatable 值并调用 onNodeChangeCallback。在 virtual  kubelet 机制中,NodeProvider 是被上层 NodeController 调用 NotifyNodeStatus 方法,来监控 virtual node 的变化。
  3. 实际的状态更新由 NodeController 定义的回调函数将节点信息压入 channel,NodeController 的控制循环实时异步地将资源变化向本集群的 api server 更新。

可以看到 home cluster 和 foreign cluster 没有本质上的区别,两者可以相互使用对方允许共享的机器资源。当然,集群 A 也可以配置成不贡献自己的资源出去,只使用别的集群分享出来的资源。

总结

本文介绍了 KubeFed/Liqo 两个开源项目多集群的资源管理和 pod 调度。

KubeFed 的资源调度总体上比较静态,需要创建 workload 之前确保各集群有充足资源。它的动态调度能力有限,因为只能对 Deployment/ReplicaSet 开启。当 KubeFed 下发 pod 到集群出现 pod pending 的情况时,动态调度的能力能够将 pod 迁移到其他集群。

Liqo 是能做到动态的资源发现和 pod 调度,但是它的方法是将一个集群抽象成一个工作节点。这种方式必然忽略了资源碎片的现象,使得虚拟节点的资源余量存在失真。比如集群内的 2 个节点共剩余 40 核可用资源,并不一定代表集群还能调度一个 40 核资源的 pod。但是从 Liqo 的方式来看,这个集群是能够调度 40 核 pod 的。并且目前来看,如果集群内出现 pod pending 的情况,也没法自动迁移 pod 到其他集群。

不过 Liqo 的整个思想是比较新颖的,通过对等的 P2P 方式将多个集群聚合成一个大的可用资源池。对于现有集群也不会引入一套新的 API。或许 Liqo 可以引入 descheduler 将 pending pod 迁移到其他机器来解决资源余量的误差问题。

参考资料

引用链接

[1]KubeFed: https://github.com/kubernetes-sigs/kubefed

[2]Liqo: https://github.com/liqotech/liqo

[3]Virtual Kubelet: https://github.com/virtual-kubelet/virtual-kubelet

[4]Virtual Kubelet: https://www.huweihuang.com/kubernetes-notes/virtual-kubelet/virtual-kubelet.html

来源:奇妙的Linux世界内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯