本教程介绍了如何在单个 Google Kubernetes Engine (GKE) 集群内高效地在训练和推理服务工作负载之间共享加速器资源。通过在单个集群中分布混合工作负载,您可以提高资源利用率、简化集群管理、减少因加速器数量限制而产生的问题,并提高整体性价比。
在本教程中,您将使用 Gemma 2 大语言模型 (LLM) 进行推理,并使用 Hugging Face TGI(文本生成接口)服务框架以及低优先级 LLM 微调作业创建高优先级服务部署。这两项工作负载都运行在使用 NVIDIA L4 GPU 的单个集群上。您可以使用 Kueue(一个开源 Kubernetes 原生作业队列系统)来管理和调度工作负载。借助 Kueue,您可以优先处理服务任务并抢占优先级较低的训练作业,以优化资源利用率。随着广告投放需求的减少,您可以重新分配释放的加速器,以恢复训练作业。您可以使用 Kueue 和优先级类在整个过程中管理资源配额。
本教程适用于希望在 GKE 集群上训练和托管机器学习 (ML) 模型,同时希望降低费用和管理开销(尤其是在处理数量有限的加速器时)的机器学习 (ML) 工程师、平台管理员和运维人员,以及数据和 AI 专家。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务。
在阅读本页面之前,请确保您熟悉以下内容:
目标
阅读完本指南后,您应该能够执行以下步骤:
- 配置高优先级的广告投放部署。
- 设置优先级较低的训练作业。
- 实现抢占策略,以应对不同的需求。
- 使用 Kueue 在训练任务和服务任务之间管理资源分配。
准备工作
- Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the required APIs.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the required APIs.
-
Make sure that you have the following role or roles on the project:
roles/container.admin
,roles/iam.serviceAccountAdmin
Check for the roles
-
In the Google Cloud console, go to the IAM page.
Go to IAM - Select the project.
-
In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.
- For all rows that specify or include you, check the Role column to see whether the list of roles includes the required roles.
Grant the roles
-
In the Google Cloud console, go to the IAM page.
进入 IAM - 选择项目。
- 点击 授予访问权限。
-
在新的主账号字段中,输入您的用户标识符。 这通常是 Google 账号的电子邮件地址。
- 在选择角色列表中,选择一个角色。
- 如需授予其他角色,请点击 添加其他角色,然后添加其他各个角色。
- 点击 Save(保存)。
-
- 如果您还没有 Hugging Face 账号,请创建一个。
- 确保您的项目具有足够的 GPU 配额。如需了解详情,请参阅 GPU 简介和分配配额。
准备环境
在本部分中,您将预配部署 TGI 和推理和训练工作负载所需的资源。
获取对模型的访问权限
如需获取对 Gemma 模型的访问权限以便部署到 GKE,您必须先签署许可同意协议,然后生成 Hugging Face 访问令牌。
- 签署许可同意协议。访问模型意见征求页面,使用您的 Hugging Face 账号验证同意情况,然后接受模型条款。
生成访问令牌。如需通过 Hugging Face 访问该模型,您需要拥有 Hugging Face 令牌。如果您还没有令牌,请按照以下步骤生成新令牌:
- 点击您的个人资料 > 设置 > 访问令牌。
- 选择新建令牌 (New Token)。
- 指定您选择的名称和一个至少为
Read
的角色。 - 选择生成令牌。
- 将生成的令牌复制到剪贴板。
启动 Cloud Shell
在本教程中,您将使用 Cloud Shell 来管理Google Cloud上托管的资源。Cloud Shell 预安装了本教程所需的软件,包括 kubectl
、
gcloud CLI 和 Terraform。
如需使用 Cloud Shell 设置您的环境,请按照以下步骤操作:
在 Google Cloud 控制台中,点击 Google Cloud 控制台中的 激活 Cloud Shell 以启动 Cloud Shell 会话。此操作会在 Google Cloud 控制台的底部窗格中启动会话。
设置默认环境变量:
gcloud config set project PROJECT_ID export PROJECT_ID=$(gcloud config get project)
将 PROJECT_ID 替换为您的 Google Cloud 项目 ID。
从 GitHub 克隆示例代码。在 Cloud Shell 中,运行以下命令:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/ cd kubernetes-engine-samples/ai-ml/mix-train-and-inference export EXAMPLE_HOME=$(pwd)
创建 GKE 集群
您可以为混合工作负载使用 Autopilot 或 Standard 集群。我们建议您使用 Autopilot 集群获得全托管式 Kubernetes 体验。如需选择最适合您的工作负载的 GKE 操作模式,请参阅选择 GKE 操作模式。
Autopilot
在 Cloud Shell 中设置默认环境变量:
export HF_TOKEN=HF_TOKEN export REGION=REGION export CLUSTER_NAME="llm-cluster" export PROJECT_NUMBER=$(gcloud projects list \ --filter="$(gcloud config get-value project)" \ --format="value(PROJECT_NUMBER)") export MODEL_BUCKET="model-bucket-$PROJECT_ID"
替换以下值:
- HF_TOKEN:您之前生成的 Hugging Face 令牌。
- REGION:支持您要使用的加速器类型的区域,例如,对于 L4 GPU,为
us-central1
。
您可以调整 MODEL_BUCKET 变量,它表示存储经过训练的模型权重的 Cloud Storage 存储桶。
创建 Autopilot 集群:
gcloud container clusters create-auto ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION} \ --release-channel=rapid
为微调作业创建 Cloud Storage 存储桶:
gcloud storage buckets create gs://${MODEL_BUCKET} \ --location ${REGION} \ --uniform-bucket-level-access
如需授予对 Cloud Storage 存储桶的访问权限,请运行以下命令:
gcloud storage buckets add-iam-policy-binding "gs://$MODEL_BUCKET" \ --role=roles/storage.objectAdmin \ --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/llm/sa/default \ --condition=None
如需获取集群的身份验证凭据,请运行以下命令:
gcloud container clusters get-credentials llm-cluster \ --region=$REGION \ --project=$PROJECT_ID
为您的部署创建一个命名空间。在 Cloud Shell 中,运行以下命令:
kubectl create ns llm
标准
在 Cloud Shell 中设置默认环境变量:
export HF_TOKEN=HF_TOKEN export REGION=REGION export CLUSTER_NAME="llm-cluster" export GPU_POOL_MACHINE_TYPE="g2-standard-24" export GPU_POOL_ACCELERATOR_TYPE="nvidia-l4" export PROJECT_NUMBER=$(gcloud projects list \ --filter="$(gcloud config get-value project)" \ --format="value(PROJECT_NUMBER)") export MODEL_BUCKET="model-bucket-$PROJECT_ID"
替换以下值:
- HF_TOKEN:您之前生成的 Hugging Face 令牌。
- REGION:支持您要使用的加速器类型的区域,例如,对于 L4 GPU,为
us-central1
。
您可以调整以下变量:
- GPU_POOL_MACHINE_TYPE:您要在所选区域中使用的节点池机器系列。此值取决于您选择的加速器类型。如需了解详情,请参阅在 GKE 上使用 GPU 的限制。例如,本教程使用
g2-standard-24
,每个节点连接两个 GPU。如需查看最新的可用 GPU 列表,请参阅面向计算工作负载的 GPU。 - GPU_POOL_ACCELERATOR_TYPE:您所选区域支持的加速器类型。例如,本教程使用
nvidia-l4
。如需查看最新的可用 GPU 列表,请参阅面向计算工作负载的 GPU。 - MODEL_BUCKET:您存储训练好的模型权重的 Cloud Storage 存储桶。
创建 Standard 集群:
gcloud container clusters create ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION} \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --release-channel=rapid \ --machine-type=e2-standard-4 \ --addons GcsFuseCsiDriver \ --num-nodes=1
创建用于推理和微调工作负载的 GPU 节点池:
gcloud container node-pools create gpupool \ --accelerator type=${GPU_POOL_ACCELERATOR_TYPE},count=2,gpu-driver-version=latest \ --project=${PROJECT_ID} \ --location=${REGION} \ --node-locations=${REGION}-a \ --cluster=${CLUSTER_NAME} \ --machine-type=${GPU_POOL_MACHINE_TYPE} \ --num-nodes=3
为微调作业创建 Cloud Storage 存储桶:
gcloud storage buckets create gs://${MODEL_BUCKET} \ --location ${REGION} \ --uniform-bucket-level-access
如需授予对 Cloud Storage 存储桶的访问权限,请运行以下命令:
gcloud storage buckets add-iam-policy-binding "gs://$MODEL_BUCKET" \ --role=roles/storage.objectAdmin \ --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/llm/sa/default \ --condition=None
如需获取集群的身份验证凭据,请运行以下命令:
gcloud container clusters get-credentials llm-cluster \ --region=$REGION \ --project=$PROJECT_ID
为您的部署创建一个命名空间。在 Cloud Shell 中,运行以下命令:
kubectl create ns llm
为 Hugging Face 凭据创建 Kubernetes Secret
如需创建包含 Hugging Face 令牌的 Kubernetes Secret,请运行以下命令:
kubectl create secret generic hf-secret \
--from-literal=hf_api_token=$HF_TOKEN \
--dry-run=client -o yaml | kubectl apply --namespace=llm --filename=-
配置 Kueue
在本教程中,Kueue 是中央资源管理器,可在训练和服务工作负载之间高效共享 GPU。Kueue 通过定义资源要求(“变种”)、通过队列确定工作负载优先级(服务任务的优先级高于训练任务),以及根据需求和优先级动态分配资源来实现这一点。本教程使用工作负载资源类型分别对推理和微调工作负载进行分组。
Kueue 的抢占功能可确保在资源紧缺时暂停或驱逐优先级较低的训练作业,从而确保高优先级服务工作负载始终拥有必要的资源。
如需使用 Kueue 控制推理服务器部署,您可以使用 Kustomize 应用自定义配置,以启用 v1/pod
集成,确保服务器 Pod 带有 "kueue-job: true"
标签。
在
/kueue
目录中,查看kustomization.yaml
中的代码。此清单会使用自定义配置安装 Kueue 资源管理器。在
/kueue
目录中,查看patch.yaml
中的代码。此 ConfigMap 会自定义 Kueue,以管理带有"kueue-job: true"
标签的 Pod。在 Cloud Shell 中,运行以下命令以安装 Kueue:
cd ${EXAMPLE_HOME} kubectl kustomize kueue |kubectl apply --server-side --filename=-
等待 Kueue Pod 准备就绪:
watch kubectl --namespace=kueue-system get pods
输出应类似如下所示:
NAME READY STATUS RESTARTS AGE kueue-controller-manager-bdc956fc4-vhcmx 2/2 Running 0 3m15s
在
/workloads
目录中,查看flavors.yaml
、cluster-queue.yaml
和local-queue.yaml
文件。以下清单指定了 Kueue 如何管理资源配额:ResourceFlavor
此清单在 Kueue 中定义了默认的 ResourceFlavor,用于资源管理。
ClusterQueue
此清单会设置一个 Kueue ClusterQueue,并为 CPU、内存和 GPU 设置资源限制。
本教程中使用的节点挂接了两个 Nvidia L4 GPU,相应的节点类型为
g2-standard-24
,提供 24 个 vCPU 和 96 GB RAM。示例代码展示了如何将工作负载的资源用量限制为最多 6 个 GPU。ClusterQueue 配置中的
preemption
字段会引用 PriorityClass,以确定在资源紧缺时可以抢占哪些 Pod。LocalQueue
此清单会在
llm
命名空间中创建一个名为lq
的 Kueue LocalQueue。查看
default-priorityclass.yaml
、low-priorityclass.yaml
和high-priorityclass.yaml
文件。这些清单定义了 Kubernetes 调度所需的 PriorityClass 对象。默认优先级
低优先级
高优先级
运行以下命令以应用相应的清单,从而创建 Kueue 和 Kubernetes 对象。
cd ${EXAMPLE_HOME}/workloads kubectl apply --filename=flavors.yaml kubectl apply --filename=default-priorityclass.yaml kubectl apply --filename=high-priorityclass.yaml kubectl apply --filename=low-priorityclass.yaml kubectl apply --filename=cluster-queue.yaml kubectl apply --filename=local-queue.yaml --namespace=llm
部署 TGI 推理服务器
在本部分中,您将部署 TGI 容器以提供 Gemma 2 模型。
在
/workloads
目录中,查看tgi-gemma-2-9b-it-hp.yaml
文件。此清单定义了一个 Kubernetes 部署,用于部署 TGI 服务运行时和gemma-2-9B-it
模型。部署会优先处理推理任务,并为模型使用两个 GPU。它通过设置
NUM_SHARD
环境变量,使用张量并行处理将模型放入 GPU 显存中。通过运行以下命令来应用清单:
kubectl apply --filename=tgi-gemma-2-9b-it-hp.yaml --namespace=llm
部署操作需要几分钟才能完成。
如需检查 GKE 是否成功创建了部署,请运行以下命令:
kubectl --namespace=llm get deployment
输出应类似如下所示:
NAME READY UP-TO-DATE AVAILABLE AGE tgi-gemma-deployment 1/1 1 1 5m13s
验证 Kueue 配额管理
在本部分中,您将确认 Kueue 是否正确强制执行了您的部署的 GPU 配额。
如需检查 Kueue 是否知晓您的部署,请运行以下命令以检索 Workload 对象的状态:
kubectl --namespace=llm get workloads
输出应类似如下所示:
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE pod-tgi-gemma-deployment-6bf9ffdc9b-zcfrh-84f19 lq cluster-queue True 8m23s
如需测试替换配额限制,请将部署扩缩为四个副本:
kubectl scale --replicas=4 deployment/tgi-gemma-deployment --namespace=llm
运行以下命令可查看 GKE 部署的副本数量:
kubectl get workloads --namespace=llm
输出应类似如下所示:
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE pod-tgi-gemma-deployment-6cb95cc7f5-5thgr-3f7d4 lq cluster-queue True 14s pod-tgi-gemma-deployment-6cb95cc7f5-cbxg2-d9fe7 lq cluster-queue True 5m41s pod-tgi-gemma-deployment-6cb95cc7f5-tznkl-80f6b lq 13s pod-tgi-gemma-deployment-6cb95cc7f5-wd4q9-e4302 lq cluster-queue True 13s
输出结果显示,由于 Kueue 强制执行的资源配额,系统仅接受了三个 Pod。
运行以下命令可显示
llm
命名空间中的 Pod:kubectl get pod --namespace=llm
输出应类似如下所示:
NAME READY STATUS RESTARTS AGE tgi-gemma-deployment-7649884d64-6j256 1/1 Running 0 4m45s tgi-gemma-deployment-7649884d64-drpvc 0/1 SchedulingGated 0 7s tgi-gemma-deployment-7649884d64-thdkq 0/1 Pending 0 7s tgi-gemma-deployment-7649884d64-znvpb 0/1 Pending 0 7s
现在,将部署缩减回 1。在部署微调作业之前,必须先执行此步骤,否则由于推理作业具有优先级,微调作业将无法被接受。
kubectl scale --replicas=1 deployment/tgi-gemma-deployment --namespace=llm
行为说明
由于您在 ClusterQueue 配置中设置了 GPU 配额限制,因此伸缩示例只会产生三个副本(尽管扩缩到四个)。ClusterQueue 的 spec.resourceGroups
部分为 nvidia.com/gpu
定义了“6”的 nominalQuota。该部署指定每个 Pod 需要“2”个 GPU。因此,ClusterQueue 一次最多只能容纳 3 个部署副本(因为 3 个副本 * 每个副本 2 个 GPU = 6 个 GPU,即总配额)。
当您尝试扩缩到 4 个副本时,Kueue 会识别出此操作会超出 GPU 配额,并阻止调度第四个副本。这由第四个 Pod 的 SchedulingGated
状态表示。此行为演示了 Kueue 的资源配额强制执行。
部署训练作业
在本部分中,您将为 Gemma 2 模型部署优先级较低的微调作业,该模型需要在两个 Pod 中使用四个 GPU。此作业将使用 ClusterQueue 中的剩余 GPU 配额。作业使用预构建映像并保存检查点,以便从中间结果重新启动。
微调作业使用 b-mc2/sql-create-context
数据集。微调作业的源代码可在代码库中找到。
查看
fine-tune-l4.yaml
文件。此清单定义了微调作业。应用清单以创建微调作业:
cd ${EXAMPLE_HOME}/workloads sed -e "s/<MODEL_BUCKET>/$MODEL_BUCKET/g" \ -e "s/<PROJECT_ID>/$PROJECT_ID/g" \ -e "s/<REGION>/$REGION/g" \ fine-tune-l4.yaml |kubectl apply --filename=- --namespace=llm
验证您的部署是否正在运行。如需检查 Workload 对象的状态,请运行以下命令:
kubectl get workloads --namespace=llm
输出应类似如下所示:
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE job-finetune-gemma-l4-3316f lq cluster-queue True 29m pod-tgi-gemma-deployment-6cb95cc7f5-cbxg2-d9fe7 lq cluster-queue True 68m
接下来,运行以下命令查看
llm
命名空间中的 Pod:kubectl get pod --namespace=llm
输出应类似如下所示:
NAME READY STATUS RESTARTS AGE finetune-gemma-l4-0-vcxpz 2/2 Running 0 31m finetune-gemma-l4-1-9ppt9 2/2 Running 0 31m tgi-gemma-deployment-6cb95cc7f5-cbxg2 1/1 Running 0 70m
输出显示 Kueue 允许您的微调作业和推理服务器 Pod 运行,并根据您指定的配额限制预留正确的资源。
查看输出日志,验证您的微调作业是否已将检查点保存到 Cloud Storage 存储桶。微调作业大约需要 10 分钟才能开始保存第一个检查点。
kubectl logs --namespace=llm --follow --selector=app=finetune-job
第一个已保存检查点的输出类似于以下内容:
{"name": "finetune", "thread": 133763559483200, "threadName": "MainThread", "processName": "MainProcess", "process": 33, "message": "Fine tuning started", "timestamp": 1731002351.0016131, "level": "INFO", "runtime": 451579.89835739136} … {"name": "accelerate.utils.fsdp_utils", "thread": 136658669348672, "threadName": "MainThread", "processName": "MainProcess", "process": 32, "message": "Saving model to /model-data/model-gemma2/experiment/checkpoint-10/pytorch_model_fsdp_0", "timestamp": 1731002386.1763802, "level": "INFO", "runtime": 486753.8924217224}
在混合工作负载上测试 Kueue 抢占和动态分配
在本部分中,您将模拟推理服务器负载增加且需要扩容的情况。此场景演示了在资源受限时,Kueue 如何通过暂停和抢占优先级较低的微调作业来优先处理高优先级推理服务器。
运行以下命令,将推理服务器的副本扩缩到 2 个:
kubectl scale --replicas=2 deployment/tgi-gemma-deployment --namespace=llm
检查工作负载对象的状态:
kubectl get workloads --namespace=llm
输出类似于以下内容:
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE job-finetune-gemma-l4-3316f lq False 32m pod-tgi-gemma-deployment-6cb95cc7f5-cbxg2-d9fe7 lq cluster-queue True 70m pod-tgi-gemma-deployment-6cb95cc7f5-p49sh-167de lq cluster-queue True 14s
输出结果显示,由于增加的推理服务器副本正在使用可用的 GPU 配额,因此系统不再接受微调作业。
检查微调作业的状态:
kubectl get job --namespace=llm
输出类似于以下内容,表明微调作业状态现已暂停:
NAME STATUS COMPLETIONS DURATION AGE finetune-gemma-l4 Suspended 0/2 33m
运行以下命令以检查您的 Pod:
kubectl get pod --namespace=llm
输出类似于以下内容,表示 Kueue 终止了微调作业 Pod,以便为优先级更高的推理服务器部署释放资源。
NAME READY STATUS RESTARTS AGE tgi-gemma-deployment-6cb95cc7f5-cbxg2 1/1 Running 0 72m tgi-gemma-deployment-6cb95cc7f5-p49sh 0/1 ContainerCreating 0 91s
接下来,测试推理服务器负载减少且其 Pod 缩减的情况。运行以下命令:
kubectl scale --replicas=1 deployment/tgi-gemma-deployment --namespace=llm
运行以下命令可显示 Workload 对象:
kubectl get workloads --namespace=llm
输出类似于以下内容,表明其中一个推理服务器部署已终止,并且微调作业已重新接受。
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE job-finetune-gemma-l4-3316f lq cluster-queue True 37m pod-tgi-gemma-deployment-6cb95cc7f5-cbxg2-d9fe7 lq cluster-queue True 75m
运行以下命令以显示作业:
kubectl get job --namespace=llm
输出类似于以下内容,表示微调作业已重新运行,并从最新的可用检查点恢复。
NAME STATUS COMPLETIONS DURATION AGE finetune-gemma-l4 Running 0/2 2m11s 38m
清理
为避免因本教程中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。
删除已部署的资源
为避免系统因您在本指南中创建的资源而向您的 Google Cloud 账号收取费用,请运行以下命令:
gcloud storage rm --recursive gs://${MODEL_BUCKET}
gcloud container clusters delete ${CLUSTER_NAME} --location ${REGION}