本教程介绍了如何使用 Kueue 在 Google Kubernetes Engine (GKE) 上安排 Job,从而优化可用资源。在本教程中,您将学习如何使用 Kueue 有效管理和安排批量作业、提高资源利用率并简化工作负载管理。您为两个租户团队设置了一个共享集群,其中每个团队都有自己的命名空间,并且每个团队创建的 Job 都共享全局资源。您还可以将 Kueue 配置为根据您定义的资源配额来安排 Job。
本教程适用于想要使用 GKE 实现批量系统的云架构师和平台工程师。如需详细了解我们在 Google Cloud内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务。
在阅读本页面之前,请确保您熟悉以下内容:
背景
Job 是运行到完成的应用,例如机器学习、渲染、模拟、分析、CI/CD 和类似工作负载。
Kueue 是一个云原生 Job 调度器,使用默认的 Kubernetes 调度器、Job 控制器和集群自动扩缩器来提供端到端批处理系统。Kueue 会根据配额和层次结构,在团队之间共享资源,从而实现 Job 排队,确定 Job 应等待的时间和应开始的时间。
Kueue 具有以下特征:
- 它针对云架构进行了优化,其中资源是异构、可互换且可扩缩。
- 它提供了一组 API,用于管理弹性配额和管理 Job 队列。
- 它不会重新实现自动扩缩、Pod 调度或 Job 生命周期管理等现有功能。
- Kueue 内置了对 Kubernetes
batch/v1.Job
API 的支持。 - 它可以与其他作业 API 集成。
Kueue 会将任何 API 定义的作业用作工作负载,以避免与特定 Kubernetes Job API 混淆。
创建 ResourceFlavor
ResourceFlavor 是一种对象,用于表示集群内节点的变体,即将它们与节点标签和污点相关联。例如,您可以使用 ResourceFlavor 表示具有不同预配保证(例如 Spot 与按需)、架构(例如 x86 与 ARM CPU)、品牌和型号(例如 Nvidia A100 与 T4 GPU)的虚拟机。
在本教程中,kueue-autopilot
集群具有同构资源。因此,请为 CPU、内存、临时存储和 GPU 创建一个 ResourceFlavor,而不使用标签或污点。
kubectl apply -f flavors.yaml
创建 ClusterQueue
ClusterQueue 是集群级对象,用于管理 CPU、内存、GPU 等资源池。它负责管理 ResourceFlavor,并限制其用量并决定工作负载的允许顺序。
部署 ClusterQueue:
kubectl apply -f cluster-queue.yaml
使用顺序由 .spec.queueingStrategy
确定,其中有两种配置:
BestEffortFIFO
- 默认排队策略配置。
- 工作负载准入遵循先进先出 (FIFO) 规则,但如果配额不足以允许队列头部的工作负载,则将尝试队列中的下一项工作负载。
StrictFIFO
- 保证 FIFO 语义。
- 队列头部的工作负载可以阻止将更多工作负载加入队列,直到该工作负载获得准入许可。
在 cluster-queue.yaml
中,您可以创建一个名为 cluster-queue
的新 ClusterQueue。此 ClusterQueue 使用 flavors.yaml
中创建的变种管理四个资源:cpu
、memory
、nvidia.com/gpu
和 ephemeral-storage
。配额由工作负载 Pod 规范中的请求使用。
每个变种都包含表示为 .spec.resourceGroups[].flavors[].resources[].nominalQuota
的使用限制。在这种情况下,当且仅当满足以下条件时,ClusterQueue 才允许工作负载:
- CPU 请求的总和小于或等于 10
- 内存请求的总和小于或等于 10Gi
- GPU 请求的总和小于或等于 10
- 使用的存储空间总和小于或等于 10Gi
创建 LocalQueue
LocalQueue 是一个命名空间对象,接受来自命名空间中用户的工作负载。不同命名空间的 LocalQueue 可以指向同一个 ClusterQueue,它们可以在其中共享资源的配额。在这种情况下,命名空间 team-a
和 team-b
中的 LocalQueue 指向 .spec.clusterQueue
下的同一 ClusterQueue cluster-queue
。
每个团队都在其命名空间中将其工作负载发送到 LocalQueue。然后,ClusterQueue 会分配这些资源。
部署 LocalQueue:
kubectl apply -f local-queue.yaml
创建 Job 并观察允许的工作负载
在本部分中,您将在命名空间 team-a
中创建 Kubernetes Job。Kubernetes 中的 Job 控制器会创建一个或多个 Pod,并确保它们成功执行特定任务。
命名空间 team-a
中的作业具有以下属性:
- 它指向
lq-team-a
LocalQueue。 - 它通过将
nodeSelector
字段设置为nvidia-tesla-t4
来请求 GPU 资源。 - 它由三个 Pod 并行休眠 10 秒组成。根据
ttlSecondsAfterFinished
字段中定义的值,Job 会在 60 秒后清理。 - 它需要 1,500 milliCPU、1536 Mi 内存、1,536 Mi 临时存储空间和三个 GPU,因为有三个 Pod。
Job 还在文件 job-team-b.yaml
(其命名空间属于 team-b
)下创建,其中请求表示具有不同需求的不同团队。
如需了解详情,请参阅在 Autopilot 中部署 GPU 工作负载。
在新终端中,观察每两秒钟刷新一次的 ClusterQueue 的状态:
watch -n 2 kubectl get clusterqueue cluster-queue -o wide
在新终端中,观察节点的状态:
watch -n 2 kubectl get nodes -o wide
在新终端中,每 10 秒从命名空间
team-a
和team-b
创建到 LocalQueue 的 Job:./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
观察正在排队的 Job、在 ClusterQueue 中允许的 Job,以及使用 GKE Autopilot 启动的节点。
从命名空间
team-a
获取 Job:kubectl -n team-a get jobs
结果类似于以下内容:
NAME COMPLETIONS DURATION AGE sample-job-team-b-t6jnr 3/3 21s 3m27s sample-job-team-a-tm7kc 0/3 2m27s sample-job-team-a-vjtnw 3/3 30s 3m50s sample-job-team-b-vn6rp 0/3 40s sample-job-team-a-z86h2 0/3 2m15s sample-job-team-b-zfwj8 0/3 28s sample-job-team-a-zjkbj 0/3 4s sample-job-team-a-zzvjg 3/3 83s 4m50s
复制上一步中的 Job 名称,并通过 Workloads API 观察 Job 的准入状态和事件:
kubectl -n team-a describe workload JOB_NAME
当待处理 Job 开始从 ClusterQueue 增加时,请在正在运行的脚本上按
CTRL + C
结束脚本。完成所有 Job 后,请注意节点是否缩减。