作者:Abdullah Gharaibeh(谷歌),Aldo Culquicondor(谷歌)
无论是在本地还是在云中,集群都面临着资源使用、配额和成本管理等方面的实际限制。尽管有自动伸缩功能,集群的容量是有限的。因此,用户需要一种简单的方法来公平有效地共享资源。
在本文中,我们将介绍Kueue[1],这是一个开源的作业(Job)排队控制器,旨在将批处理作业作为一个单元来管理。Kueue 将 pod 级别的编排留给了 Kubernetes 现有的稳定组件。Kueue 本身支持 Kubernetes Job[2] API,并提供了用于集成其他定制的批处理作业 API 的钩子。
作业排队是在本地和云环境中大规模运行批处理工作负载的一项关键功能。作业排队的主要目的,是管理对多个租户共享的有限资源池的访问。作业排队决定哪些作业应该等待,哪些作业可以立即启动,以及它们可以使用哪些资源。
一些最理想的作业排队要求包括:
普通的 Kubernetes 不能满足上述要求。在正常情况下,一旦创建了一个作业,作业控制器立即创建 pod,kube-scheduler 不断尝试将 pod 分配给节点。在大规模环境,这种情况会让控制层工作到死。目前也没有好的方法在作业级别控制哪些作业应该首先获得哪些资源,也没有方法表示顺序或公平共享。当前的 ResourceQuota 模型不太适合这些需求,因为配额是在资源创建时强制执行的,并且没有请求排队。ResourceQuotas 的目的,是提供一种内置的可靠性机制,其中包含管理员保护集群免于故障转移所需的策略。
在 Kubernetes 生态系统中,有几种作业调度的解决方案。然而,我们发现这些替代方案存在以下一个或多个问题:
通过 Kueue,我们决定在 Kubernetes 上采用一种不同的作业排队方法,这种方法基于以下几个方面:
为了使这种方法可行,Kueue 需要设定来影响那些已建立的组件的行为,以便它可以有效地管理何时何地开始一项工作。我们以两种功能的形式将这些设定添加到 Job API 中:
请注意,任何自定义作业 API 都可以由 Kueue 管理,只要该 API 提供上述两种功能。
Kueue 定义了新的 API 来满足本文开头提到的需求。三个主要的 API 是:
更多细节,请看API 概念文档[7]。虽然这三个 API 看起来复杂,但 Kueue 的大部分操作都是围绕 ClusterQueue 进行的;ResourceFlavor 和 LocalQueue APIs 主要是组织包装器。
想象一下在云上的 Kubernetes 集群上运行批处理工作负载的如下设置:
作为批处理系统的管理员,你定义了两种 ResourceFlavors 来表示两种类型的节点:
---
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ResourceFlavor
metadata:
name: ondemand
labels:
instance-type: ondemand
---
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ResourceFlavor
metadata:
name: spot
labels:
instance-type: spot
taints:
- effect: NoSchedule
key: spot
value: "true"
然后,通过创建 ClusterQueue 来定义配额,如下所示:
apiVersion: kueue.x-k8s.io/v1alpha2
kind: ClusterQueue
metadata:
name: research-pool
spec:
namespaceSelector: {}
resources:
- name: "cpu"
flavors:
- name: ondemand
quota:
min: 1000
- name: spot
quota:
min: 2000
请注意,ClusterQueue 资源中风格的顺序很重要:Kueue 将尝试根据顺序将作业放入可用的配额中,除非作业与特定的风格有明确的关联。
对于每个命名空间,你定义一个指向上面的 ClusterQueue 的 LocalQueue:
apiVersion: kueue.x-k8s.io/v1alpha2
kind: LocalQueue
metadata:
name: training
namespace: team-ml
spec:
clusterQueue: research-pool
管理员创建上述设置一次。批处理用户可以通过在其命名空间中列出本地队列来找到允许他们提交的队列。该命令类似于:kubectl get -n my-namespace localqueues
要提交作业,创建一个 Job 并按如下方式设置 kueue.x-k8s.io/queue-name 注释:
apiVersion: batch/v1
kind: Job
metadata:
generateName: sample-job-
annotations:
kueue.x-k8s.io/queue-name: training
spec:
parallelism: 3
completions: 3
template:
spec:
tolerations:
- key: spot
operator: "Exists"
effect: "NoSchedule"
containers:
- name: example-batch-workload
image: registry.example/batch/calculate-pi:3.14
args: ["30s"]
resources:
requests:
cpu: 1
restartPolicy: Never
Job 一旦创建,Kueue 就进行干预以暂停它。一旦 Job 位于 ClusterQueue 的头部,Kueue 就会通过检查作业请求的资源是否符合可用配额来评估它是否可以启动。
在上面的例子中,任务允许使用 spot 资源。如果先前允许的作业消耗了所有现有的 on-demand 配额,但不是所有的 spot 配额,则 Kueue 会使用 spot 配额来允许作业。Kueue 通过向作业对象发出一个更新来实现这一点:
最后,如果有符合节点选择器条件的可用空节点,那么 kube-scheduler 将直接调度 pod。如果没有,那么 kube-scheduler 最初会将 pod 标记为不可调度的,这将触发集群自动伸缩程序来提供新节点。
上面的例子展示了 Kueue 的一些特性,包括对配额的支持、资源灵活性,以及与集群自动缩放器的集成。Kueue 还支持公平共享、作业优先级和不同的排队策略。查看Kueue 文档[9],了解更多关于这些特性,以及如何使用 Kueue 的信息。
我们计划在 Kueue 中添加一些特性,比如分级配额、预算和对动态工作大小的支持。在不久的将来,我们将致力于增加对工作抢占的支持。
Github 上有最新的Kueue 版本[10];如果你在 Kubernetes 上运行批处理工作负载(需要 1.22 或更高版本),请尝试一下。我们正处于这个项目的早期阶段,我们正在寻求所有级别的反馈,主要或次要的,所以请不要犹豫来联系。我们也向其他贡献者开放,无论是修复或报告错误,还是帮助添加新功能或编写文档。你可以通过我们的仓库[11]、邮件列表[12]或Slack[13]与我们联系。
最后但同样重要的是,感谢所有使这个项目成为可能的贡献者[14]!
[1]
Kueue: https://github.com/kubernetes-sigs/kueue/tree/main/docs#readme
[2]
Job: https://kubernetes.io/docs/concepts/workloads/controllers/job/
[3]
IndexedJob: https://kubernetes.io/blog/2021/04/19/introducing-indexed-jobs
[4]
修复了与 pod 跟踪相关的长期问题: https://kubernetes.io/docs/concepts/workloads/controllers/job/#job-tracking-with-finalizers
[5]
Suspend 字段: https://kubernetes.io/docs/concepts/workloads/controllers/job/#suspending-a-job
[6]
可变调度指令: https://kubernetes.io/docs/concepts/workloads/controllers/job/#mutable-scheduling-directives
[7]
API 概念文档: https://sigs.k8s.io/kueue/docs/concepts
[8]
cluster-autoscaler: https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
[9]
Kueue 文档: https://github.com/kubernetes-sigs/kueue/tree/main/docs
[10]
Kueue 版本: https://github.com/kubernetes-sigs/kueue/releases
[11]
仓库: http://sigs.k8s.io/kueue
[12]
邮件列表: https://groups.google.com/a/kubernetes.io/g/wg-batch
[13]
Slack: https://kubernetes.slack.com/messages/wg-batch
[14]
贡献者: https://github.com/kubernetes-sigs/kueue/graphs/contributors