本页面介绍了如何使用灵活启动(带已排队的预配)(由动态工作负载调度器提供支持)优化 GPU 大规模批量工作负载和 AI 工作负载的 GPU 可获取性。
在阅读本页面之前,请确保您熟悉以下内容:
本指南适用于机器学习 (ML) 工程师、平台管理员和运维人员,以及对使用 Kubernetes 容器编排功能运行批量工作负载感兴趣的数据和 AI 专家。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务。
灵活启动(带已排队的预配)的工作原理
如果使用灵活启动(带已排队的预配),GKE 会同时分配所有请求的资源。灵活启动(带已排队的预配)使用以下工具:
- 灵活启动(带已排队的预配)基于动态工作负载调度器,并结合了 Provisioning Request 自定义资源定义 (CRD)。这些工具会根据可用资源和工作负载要求管理分配的容量。
- (可选)Kueue 可自动管理灵活启动(带已排队的预配)请求的生命周期。Kueue 可实现作业排队,并自动处理 Provisioning Request 生命周期。
如需使用灵活启动(带已排队的预配),您必须在创建节点池时添加 --flex-start
和 --enable-queued-provisioning
标志。
如果工作负载满足以下条件,请使用“灵活启动(带已排队的预配)”来处理大规模批处理和 AI 工作负载:
- 工作负载的开始时间灵活。
- 您的工作负载需要同时在多个节点上运行。
对于可在单个节点上运行的较小工作负载,请使用灵活启动。如需详细了解如何在 GKE 中预配 GPU,请参阅为 AI 工作负载获取加速器。
准备工作
在开始之前,请确保您已执行以下任务:
- 启用 Google Kubernetes Engine API。 启用 Google Kubernetes Engine API
- 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行
gcloud components update
以获取最新版本。
确保您拥有 1.32.2-gke.1652000 版或更高版本的 GKE 集群。
确保您管理使用动态工作负载调度器的工作负载中的中断,以防止工作负载中断。
确保您已熟悉灵活启动(带已排队的预配)的限制。
使用 Standard 集群时,请确保您至少维护了一个未启用灵活启动(带已排队的预配)的节点池,以便集群能够正常运行。
使用启用了灵活启动(带已排队的预配)的节点池
本部分仅适用于 Standard 集群。
您可以使用以下任一方法来指定灵活启动(带已排队的预配)可用于集群中的特定节点池:
创建节点池
使用 gcloud CLI 创建一个启用了灵活启动(带已排队的预配)的节点池:
gcloud container node-pools create NODEPOOL_NAME \
--cluster=CLUSTER_NAME \
--location=LOCATION \
--enable-queued-provisioning \
--accelerator type=GPU_TYPE,count=AMOUNT,gpu-driver-version=DRIVER_VERSION \
--machine-type=MACHINE_TYPE \
--flex-start \
--enable-autoscaling \
--num-nodes=0 \
--total-max-nodes TOTAL_MAX_NODES \
--location-policy=ANY \
--reservation-affinity=none \
--no-enable-autorepair
替换以下内容:
NODEPOOL_NAME
:您为节点池选择的名称。CLUSTER_NAME
:集群的名称。LOCATION
:集群的 Compute Engine 区域,例如us-central1
。GPU_TYPE
:GPU 类型。AMOUNT
:要挂接到节点池中节点的 GPU 数量。DRIVER_VERSION
:要安装的 NVIDIA 驱动程序版本。可以是以下各项之一:default
:为您的 GKE 版本安装默认驱动程序版本。latest
:为您的 GKE 版本安装最新可用的驱动程序版本。仅适用于使用 Container-Optimized OS 的节点。
TOTAL_MAX_NODES
:整个节点池自动扩缩的节点数上限。MACHINE_TYPE
:节点的 Compute Engine 机器类型。最佳实践: 使用加速器优化机器类型可提高 AI/ML 工作负载的性能和效率。
您可以视需要使用以下标志:
--node-locations=COMPUTE_ZONES
:GKE 在其中创建 GPU 节点的一个或多个可用区的英文逗号分隔列表。可用区必须与集群位于同一区域。选择有可用 GPU 的可用区。--enable-gvnic
:此标志用于在 GPU 节点池上启用 gVNIC,以提高网络流量速度。
此命令会创建具有以下配置的节点池:
--flex-start
标志与--enable-queued-provisioning
标志结合使用时,会指示 GKE 创建一个启用了灵活启动(带已排队的预配)的节点池,并向该节点池添加cloud.google.com/gke-queued
污点。- GKE 支持排队预配和集群自动扩缩。
- 节点池最初没有节点。
--no-enable-autorepair
标志会停用自动修复功能,这可能会中断在修复后的节点上运行的工作负载。
启用节点自动预配功能,以创建用于灵活启动(带已排队的预配)的节点池
对于运行 1.29.2-gke.1553000 版或更高版本的集群,您可以使用节点自动预配来管理节点池,以实现灵活启动(带已排队的预配)。启用节点自动预配后,GKE 会创建包含关联工作负载所需资源的节点池。
如需启用节点自动预配功能,请考虑以下设置,并完成预配 GPU 限制中的步骤:
- 启用该功能时,请指定灵活启动(带已排队的预配)所需的资源。如需列出可用的
resourceTypes
,请运行gcloud compute accelerator-types list
命令。 - 使用
--no-enable-autoprovisioning-autorepair
标志可停用节点自动修复功能。 - 允许 GKE 在自动预配的 GPU 节点中自动安装 GPU 驱动程序。如需了解详情,请参阅将节点自动预配与 GPU 搭配使用来安装驱动程序。
通过灵活启动(带已排队的预配)运行批处理和 AI 工作负载
如需通过灵活启动(带已排队的预配)运行批处理工作负载,请使用以下任一配置:
使用 Kueue 的作业的灵活启动(带已排队的预配):您可以将灵活启动(带已排队的预配)与 Kueue 搭配使用,以自动执行 Provisioning Request 请求的生命周期。Kueue 会实现作业排队,并观察灵活启动(带已排队的预配)的状态。Kueue 会根据配额以及在团队之间公平共享资源的层次结构,确定 Job 应等待的时间和应开始的时间。
不使用 Kueue 的作业的灵活启动(带已排队的预配):当您使用自己的内部批量调度工具或平台时,可以在不使用 Kueue 的情况下使用灵活启动(带已排队的预配)。您手动创建和取消 Provisioning Request。
使用 Kueue 通过灵活启动(带已排队的预配)运行批处理和 AI 工作负载。
使用 Kueue 的作业的灵活启动(带已排队的预配)
以下部分介绍了如何为使用 Kueue 的作业配置灵活启动(带已排队的预配):
- 灵活启动(带已排队的预配)节点池设置。
- 预留和灵活启动(带已排队的预配)节点池设置。
本部分使用 ai-on-gke
仓库的 dws-examples
目录中的示例。我们已根据 Apache2 许可在 dws-examples
目录中发布示例。
您需要拥有管理员权限才能安装 Kueue。如需获得这些权限,请确保您已获得 IAM 角色 roles/container.admin
。如需详细了解 GKE IAM 角色,请参阅创建 IAM 允许政策指南。
准备环境
在 Cloud Shell 中,运行以下命令:
git clone https://github.com/GoogleCloudPlatform/ai-on-gke cd ai-on-gke/tutorials-and-examples/workflow-orchestration/dws-examples
在集群中安装最新 Kueue 版本:
VERSION=KUEUE_VERSION kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/$VERSION/manifests.yaml
将 KUEUE_VERSION 替换为最新版 Kueue。
如果您在 0.7.0
之前的版本中使用 Kueue,请通过将 ProvisioningACC
特性门控设置为 true
来更改 Kueue 特性门控配置。如需详细了解说明和默认门控值,请参阅 Kueue 的特性门控。如需详细了解 Kueue 安装,请参阅安装。
为动态工作负载调度器节点池专用设置创建 Kueue 资源
使用以下清单时,创建名为 dws-cluster-queue
的集群级队列和名为 dws-local-queue
的 LocalQueue 命名空间。在此命名空间中引用 dws-cluster-queue
队列的作业使用灵活启动(带已排队的预配)来获取 GPU 资源。
此集群的队列具有较高的配额限制,并且仅启用了灵活启动(带已排队的预配)集成。如需详细了解 Kueue API 以及如何设置限制,请参阅 Kueue 概念。
部署 LocalQueue:
kubectl create -f ./dws-queues.yaml
输出类似于以下内容:
resourceflavor.kueue.x-k8s.io/default-flavor created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created
clusterqueue.kueue.x-k8s.io/dws-cluster-queue created
localqueue.kueue.x-k8s.io/dws-local-queue created
如果您要运行在其他命名空间中使用灵活启动(带已排队的预配)的作业,可以使用上述模板创建其他 LocalQueues
。
运行 Job
在以下清单中,示例作业使用灵活启动(带已排队的预配):
此清单包含以下与灵活启动(带已排队的预配)配置相关的字段:
kueue.x-k8s.io/queue-name: dws-local-queue
标签指示 GKE 由 Kueue 负责编排该 Job。此标签还定义了 Job 排入的队列。suspend: true
标志指示 GKE 创建 Job 资源,但尚不调度 Pod。在节点准备好执行 Job 时,Kueue 会将此标志更改为false
。nodeSelector
会告知 GKE 仅在指定的节点池上调度作业。该值应与启用了已排队预配的节点池的名称NODEPOOL_NAME
匹配。
运行 Job:
kubectl create -f ./job.yaml
输出类似于以下内容:
job.batch/sample-job created
检查作业的状态:
kubectl describe job sample-job
输出类似于以下内容:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Suspended 5m17s job-controller Job suspended Normal CreatedWorkload 5m17s batch/job-kueue-controller Created Workload: default/job-sample-job-7f173 Normal Started 3m27s batch/job-kueue-controller Admitted by clusterQueue dws-cluster-queue Normal SuccessfulCreate 3m27s job-controller Created pod: sample-job-9qsfd Normal Resumed 3m27s job-controller Job resumed Normal Completed 12s job-controller Job completed
灵活启动(带已排队的预配)的 Kueue 集成还支持开源生态系统中提供的其他工作负载类型,如下所示:
- RayJob
- JobSet v0.5.2 或更高版本
- Kubeflow MPIJob、TFJob、PyTorchJob.
- 工作流编排器常用的 Kubernetes Pod
- Flux 迷你集群
如需详细了解此支持,请参阅 Kueue 的批处理用户。
为预留和动态工作负载调度器节点池设置创建 Kueue 资源
使用以下清单,您可以创建两个与两个不同的节点池(reservation-nodepool
和 dws-nodepool
)相关联的 ResourceFlavors
。这些节点池的名称仅作示例之用。根据您的节点池配置修改这些名称。此外,在 ClusterQueue
配置中,传入作业会尝试使用 reservation-nodepool
;如果容量不足,则这些作业使用动态工作负载调度器获取 GPU 资源。
此集群的队列具有较高的配额限制,并且仅启用了灵活启动(带已排队的预配)集成。如需详细了解 Kueue API 以及如何设置限制,请参阅 Kueue 概念。
使用以下命令部署清单:
kubectl create -f ./dws_and_reservation.yaml
输出类似于以下内容:
resourceflavor.kueue.x-k8s.io/reservation created
resourceflavor.kueue.x-k8s.io/dws created
clusterqueue.kueue.x-k8s.io/cluster-queue created
localqueue.kueue.x-k8s.io/user-queue created
admissioncheck.kueue.x-k8s.io/dws-prov created
provisioningrequestconfig.kueue.x-k8s.io/dws-config created
运行 Job
与上述设置相反,此清单不包含 nodeSelector
字段,因为它由 Kueue 填充,具体取决于 ClusterQueue
中的可用容量。
运行 Job:
kubectl create -f ./job-without-node-selector.yaml
输出类似于以下内容:
job.batch/sample-job-v8xwm created
如需确定作业使用的节点池,您需要了解作业使用的 ResourceFlavor。
问题排查
如需详细了解 Kueue 的问题排查,请参阅排查 Kueue 中的 Provisioning Request 问题。
不使用 Kueue 的作业的灵活启动(带已排队的预配)
定义 ProvisioningRequest 对象
通过 Provisioning Request 为每个作业创建请求。灵活启动(带已排队的预配)不会启动 Pod,只会预配节点。
创建以下
provisioning-request.yaml
清单:标准
apiVersion: v1 kind: PodTemplate metadata: name: POD_TEMPLATE_NAME namespace: NAMESPACE_NAME labels: cloud.google.com/apply-warden-policies: "true" template: spec: nodeSelector: cloud.google.com/gke-nodepool: NODEPOOL_NAME cloud.google.com/gke-flex-start: "true" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" containers: - name: pi image: perl command: ["/bin/sh"] resources: limits: cpu: "700m" nvidia.com/gpu: 1 requests: cpu: "700m" nvidia.com/gpu: 1 restartPolicy: Never --- apiVersion: autoscaling.x-k8s.io/API_VERSION kind: ProvisioningRequest metadata: name: PROVISIONING_REQUEST_NAME namespace: NAMESPACE_NAME spec: provisioningClassName: queued-provisioning.gke.io parameters: maxRunDurationSeconds: "MAX_RUN_DURATION_SECONDS" podSets: - count: COUNT podTemplateRef: name: POD_TEMPLATE_NAME
替换以下内容:
API_VERSION
:API 的版本,可以是v1
或v1beta1
。为了保持稳定并使用最新功能,我们建议您使用v1
。NAMESPACE_NAME
:Kubernetes 命名空间的名称。命名空间必须与 Pod 的命名空间相同。PROVISIONING_REQUEST_NAME
:ProvisioningRequest
的名称。您将在 Pod 注解中引用此名称。MAX_RUN_DURATION_SECONDS
:(可选)节点的最长运行时(以秒为单位),最长为 7 天(默认值)。如需了解详情,请参阅灵活启动(带已排队的预配)的工作原理。创建请求后,您无法更改此值。GKE 1.28.5-gke.1355000 版或更高版本支持此字段。COUNT
:请求的 Pod 数量。节点以原子方式调度到一个可用区中。POD_TEMPLATE_NAME
:PodTemplate
的名称。NODEPOOL_NAME
:您为节点池选择的名称。 如果您想使用自动预配的节点池,请移除此参数。
GKE 可能会在创建 Pod 期间对其应用验证和变更。
cloud.google.com/apply-warden-policies
标签可让 GKE 对 PodTemplate 对象应用相同的验证和变更。GKE 需要此标签才能计算 Pod 的节点资源需求。灵活启动(带已排队的预配)集成仅支持一个PodSet
规范。如果您想混合使用不同的 Pod 模板,请使用请求的资源最多的模板。不支持混用不同的机器类型,例如使用不同 GPU 类型的虚拟机。节点自动预配
apiVersion: v1 kind: PodTemplate metadata: name: POD_TEMPLATE_NAME namespace: NAMESPACE_NAME labels: cloud.google.com/apply-warden-policies: "true" template: spec: nodeSelector: cloud.google.com/gke-accelerator: GPU_TYPE cloud.google.com/gke-flex-start: "true" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" containers: - name: pi image: perl command: ["/bin/sh"] resources: limits: cpu: "700m" nvidia.com/gpu: 1 requests: cpu: "700m" nvidia.com/gpu: 1 restartPolicy: Never --- apiVersion: autoscaling.x-k8s.io/API_VERSION kind: ProvisioningRequest metadata: name: PROVISIONING_REQUEST_NAME namespace: NAMESPACE_NAME spec: provisioningClassName: queued-provisioning.gke.io parameters: maxRunDurationSeconds: "MAX_RUN_DURATION_SECONDS" podSets: - count: COUNT podTemplateRef: name: POD_TEMPLATE_NAME
替换以下内容:
API_VERSION
:API 的版本,可以是v1
或v1beta1
。为了保持稳定并使用最新功能,我们建议您使用v1
。NAMESPACE_NAME
:Kubernetes 命名空间的名称。命名空间必须与 Pod 的命名空间相同。PROVISIONING_REQUEST_NAME
:ProvisioningRequest
的名称。您将在 Pod 注解中引用此名称。MAX_RUN_DURATION_SECONDS
:(可选)节点的最长运行时(以秒为单位),最长为 7 天(默认值)。如需了解详情,请参阅灵活启动(带已排队的预配)的工作原理。创建请求后,您无法更改此值。GKE 1.28.5-gke.1355000 版或更高版本支持此字段。COUNT
:请求的 Pod 数量。节点以原子方式调度到一个可用区中。POD_TEMPLATE_NAME
:PodTemplate
的名称。GPU_TYPE
:GPU 硬件的类型。
GKE 可能会在创建 Pod 期间对其应用验证和变更。
cloud.google.com/apply-warden-policies
标签可让 GKE 对 PodTemplate 对象应用相同的验证和变更。GKE 需要此标签才能计算 Pod 的节点资源需求。应用清单:
kubectl apply -f provisioning-request.yaml
配置 pod
本部分使用 Kubernetes 作业来配置 Pod。但是,您也可以使用 Kubernetes JobSet 或任何其他框架(例如 Kubeflow、Ray 或自定义控制器)。在作业规范中,使用以下注解将 Pod 关联到 ProvisioningRequest
:
apiVersion: batch/v1
kind: Job
spec:
template:
metadata:
annotations:
autoscaling.x-k8s.io/consume-provisioning-request: PROVISIONING_REQUEST_NAME
autoscaling.x-k8s.io/provisioning-class-name: "queued-provisioning.gke.io"
spec:
...
Pod 注解键 consume-provisioning-request
定义要使用的 ProvisioningRequest
。GKE 使用 consume-provisioning-request
和 provisioning-class-name
注释来执行以下操作:
- 仅在通过灵活启动(带已排队的预配)预配的节点中调度 Pod。
- 为了避免在 Pod 和灵活启动(带已排队的预配)之间重复计算资源请求,集群自动扩缩器会使用排队预配。
- 注入
safe-to-evict: false
注释,以防止集群自动扩缩器在节点之间移动 Pod 并中断批处理计算。您可以通过在 Pod 注解中指定safe-to-evict: true
来更改此行为。
观察 Provisioning Request 的状态
Provisioning Request 的状态定义是否可以安排 Pod。您可以使用 Kubernetes 监视功能高效地观察更改,或您已用来跟踪 Kubernetes 对象状态的其他工具。下表介绍了 Provisioning Request 请求的可能状态以及每种可能的结果:
Provisioning Request 状态 | 说明 | 可能的结果 |
---|---|---|
待处理 | 该请求尚未被发现并且未被处理。 | 处理完毕后,请求会转换为 Accepted 或 Failed 状态。 |
Accepted=true |
请求被接受,正在等待资源变为可用状态。 | 如果找到资源并预配了节点,请求应转换为 Provisioned 状态;否则,请求应转换为 Failed 状态。 |
Provisioned=true |
节点已准备就绪。 | 您可以在 10 分钟内启动 Pod 以使用预配的资源。在此时间之后,集群自动扩缩器会将这些节点视为不需要,并将其移除。 |
Failed=true |
由于出现错误,无法预配节点。Failed=true 是一种终端状态。 |
根据条件的 Reason 和 Message 字段中的信息排查问题。创建并重试新的 Provisioning Request 请求。 |
Provisioned=false |
节点尚未完成预配。 |
如果 如果 如果 |
启动 Pod
当 Provisioning Request 请求达到 Provisioned=true
状态时,您可以运行作业来启动 Pod。这样可避免因待处理或失败的请求而导致无法调度的 Pod 大量增加,从而影响 kube-scheduler 和集群自动扩缩器的性能。
或者,如果您不介意有无法调度的 Pod,则可以与 Provisioning Request 请求并行创建 Pod。
取消 Provisioning Request 请求
如需在预配之前取消请求,您可以删除 ProvisioningRequest
:
kubectl delete provreq PROVISIONING_REQUEST_NAME -n NAMESPACE
在大多数情况下,删除 ProvisioningRequest
会阻止创建节点。不过,根据时间安排,例如如果节点已在预配,则这些节点可能仍会最终创建。在这些情况下,如果 10 分钟后未创建任何 Pod,集群自动扩缩器会移除节点。
排查配额问题
由 Provisioning Request 请求预配的所有虚拟机都使用抢占式配额。
处于 Accepted
状态的 ProvisioningRequests
的数量受专用配额限制。您可以为每个项目配置配额,每个区域对应一个配额配置。
在 Google Cloud 控制台中检查配额
如需在Google Cloud 控制台中检查配额限制的名称和当前用量,请按以下步骤操作:
前往 Google Cloud 控制台中的配额页面:
在
过滤条件框中,选择指标属性,输入active_resize_requests
,然后按 Enter 键。
默认值为 100。如需增加配额,请按照申请配额调整中列出的步骤操作。
检查 Provisioning Request 请求是否受配额限制
如果您的 Provisioning Request 请求的完成时间超出预期,请检查该请求是否受配额限制。您可能需要申请增加配额。
对于运行 1.29.2-gke.1181000 版或更高版本的集群,请检查是否存在特定的配额限制,导致您的请求无法得到满足:
kubectl describe provreq PROVISIONING_REQUEST_NAME \
--namespace NAMESPACE
输出类似于以下内容:
…
Last Transition Time: 2024-01-03T13:56:08Z
Message: Quota 'NVIDIA_P4_GPUS' exceeded. Limit: 1.0 in region europe-west4.
Observed Generation: 1
Reason: QuotaExceeded
Status: False
Type: Provisioned
…
在此示例中,GKE 无法部署节点,因为 europe-west4
区域中的配额不足。
将节点池从已排队的预配迁移到灵活启动
如需将使用 --enable-queued-provisioning
标志创建的现有节点池迁移到灵活启动,请执行以下步骤:
确保节点池为空:
kubectl get nodes -l cloud.google.com/gke-nodepool=NODEPOOL_NAME
如果该命令未返回任何节点,则您可以将节点池更新为灵活启动。
如果该命令返回节点列表,您必须先将工作负载迁移到其他节点池。
将节点池更新为灵活启动:
gcloud container node-pools update NODEPOOL_NAME \ --cluster=CLUSTER_NAME --flex-start
此操作会执行以下操作:
- 将节点池更新为灵活启动节点池。
- 应用灵活启动节点的价格。
在运行 1.32.2-gke.1652000 或更高版本(灵活启动节点的最低版本)的集群上,所有节点都使用短期升级。
后续步骤
- 详细了解 GKE 中的 GPU。
- 了解如何在 Autopilot 中部署 GPU 工作负载。
- 了解如何在机密 GKE 节点上运行 GPU(预览版)。