本教程介绍如何在单个 Google Kubernetes Engine (GKE) 集群中的训练和推理服务工作负载之间高效共享加速器资源。通过在单个集群中分布混合工作负载,您可以提高资源利用率、简化集群管理、减少加速器数量限制带来的问题,并提高整体的成本效益。
在本教程中,您将使用用于推理的 Gemma 2 大语言模型 (LLM) 和 Hugging Face TGI(文本生成接口)服务框架创建一个高优先级的服务 Deployment,并设置一个低优先级的 LLM 微调作业。这两项工作负载都在使用 NVIDIA L4 GPU 的单个集群上运行。您可以使用开源 Kubernetes 原生作业排队系统 Kueue 来管理和安排工作负载。Kueue 可让您优先运行服务任务,并抢占优先级较低的训练作业,以优化资源利用率。当服务需求减少时,您可以重新分配已释放的加速器以恢复训练作业。您可以使用 Kueue 和优先级类来管理整个流程中的资源配额。
本教程适用于机器学习 (ML) 工程师、平台管理员和运维人员,以及希望在 GKE 集群上训练和托管机器学习 (ML) 模型并降低成本和管理开销(尤其是在处理数量有限的加速器时)的数据和 AI 专家。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务。
在阅读本页面之前,请确保您熟悉以下内容:
目标
阅读完本指南后,您应该能够执行以下步骤:
- 配置高优先级的服务 Deployment。
- 设置低优先级的训练作业。
- 实施抢占策略以满足不同的需求。
- 使用 Kueue 管理训练任务和服务任务之间的资源分配。
准备工作
- 登录您的 Google Cloud 账号。如果您是 Google Cloud新手,请 创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the required APIs.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the required APIs.
Roles required to enable APIs
To enable APIs, you need the
serviceusage.services.enablepermission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.-
确保您在项目中拥有以下一个或多个角色:
roles/container.admin、roles/iam.serviceAccountAdmin检查角色
-
在 Google Cloud 控制台中,前往 IAM 页面。
转到 IAM - 选择项目。
-
在主账号列中,找到标识您或您所属群组的所有行。如需了解您属于哪些群组,请与您的管理员联系。
- 对于指定或包含您的所有行,请检查角色列以查看角色列表是否包含所需的角色。
授予角色
-
在 Google Cloud 控制台中,前往 IAM 页面。
转到 IAM - 选择项目。
- 点击 授予访问权限。
-
在新的主账号字段中,输入您的用户标识符。 这通常是 Google 账号的电子邮件地址。
- 点击选择角色,然后搜索相应角色。
- 如需授予其他角色,请点击 添加其他角色,然后添加其他各个角色。
- 点击 Save(保存)。
-
- 如果您还没有 Hugging Face 账号,请创建一个。
- 确保您的项目具有足够的 L4 GPU 配额。如需了解详情,请参阅 GPU 简介和分配配额。
准备环境
在本部分中,您将预配为推理和训练工作负载部署 TGI 和模型所需的资源。
获取对模型的访问权限
如需获取对 Gemma 模型的访问权限以便部署到 GKE,您必须先签署许可同意协议,然后生成 Huggging 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} \ --location=${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 \ --location=$REGION \ --project=$PROJECT_ID为 Deployment 创建命名空间。在 Cloud Shell 中,运行以下命令:
kubectl create ns llm
Standard
在 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} \ --location=${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 \ --location=$REGION \ --project=$PROJECT_ID为 Deployment 创建命名空间。在 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 控制推理服务器 Deployment,您需要启用 pod 集成,并配置 managedJobsNamespaceSelector 以排除 kube-system 和 kueue-system 命名空间。
在
/kueue目录中,查看kustomization.yaml中的代码。此清单会使用自定义配置安装 Kueue 资源管理器。在
/kueue目录中,查看patch.yaml中的代码。此 ConfigMap 会自定义 Kueue,以排除对kube-system和kueue-system命名空间中的 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 1/1 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字段引用 PriorityClasses,以确定在资源紧缺时哪些 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 Deployment,用于部署 TGI 服务运行时和gemma-2-9B-it模型。Deployment 是一个 Kubernetes API 对象,可让您运行在集群节点中分布的多个 Pod 副本。Deployment 会优先处理推理任务,并为模型使用两个 GPU。它通过设置
NUM_SHARD环境变量来使用张量并行处理,使模型适配 GPU 内存。通过运行以下命令来应用清单:
kubectl apply --filename=tgi-gemma-2-9b-it-hp.yaml --namespace=llm部署操作需要几分钟才能完成。
如需检查 GKE 是否已成功创建 Deployment,请运行以下命令:
kubectl --namespace=llm get deployment输出应类似如下所示:
NAME READY UP-TO-DATE AVAILABLE AGE tgi-gemma-deployment 1/1 1 1 5m13s
验证 Kueue 配额管理
在本部分中,您将确认 Kueue 已正确地为您的 Deployment 强制执行 GPU 配额。
如需检查 Kueue 是否知道您的 Deployment,请运行以下命令以检索工作负载对象的状态:
kubectl --namespace=llm get workloads输出应类似如下所示:
NAME QUEUE RESERVED IN ADMITTED FINISHED AGE pod-tgi-gemma-deployment-6bf9ffdc9b-zcfrh-84f19 lq cluster-queue True 8m23s如需测试替换配额限制,请将 Deployment 扩容到四个副本:
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 强制执行的资源配额,仅有 3 个 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现在,将 Deployment 缩减回 1。在部署微调作业之前必须执行此步骤,否则由于推理作业具有优先权,微调作业将无法被接受。
kubectl scale --replicas=1 deployment/tgi-gemma-deployment --namespace=llm
行为说明
由于您在 ClusterQueue 配置中设置的 GPU 配额限制,此扩缩示例仅会生成 3 个副本(尽管扩容到 4 个副本)。ClusterQueue 的 spec.resourceGroups 部分为 nvidia.com/gpu 定义了“6”的 NominalQuota。Deployment 指定每个 Pod 需要“2”个 GPU。因此,ClusterQueue 一次最多只能容纳 3 个 Deployment 副本(因为 3 个副本 * 每个副本 2 个 GPU = 6 个 GPU,即总配额)。
当您尝试扩容到 4 个副本时,Kueue 会识别到此操作将超出 GPU 配额,并阻止调度第 4 个副本。这由第 4 个 Pod 的 SchedulingGated 状态表明。此行为演示了 Kueue 的资源配额强制执行。
部署训练作业
在本部分中,您将为 Gemma 2 模型部署低优先级的微调作业,该模型需要在两个 Pod 中使用四个 GPU。Kubernetes 中的 Job 控制器会创建一个或多个 Pod,并帮助确保它们成功执行特定任务。
此作业将使用 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验证 Deployment 正在运行。如需检查工作负载对象的状态,请运行以下命令:
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 如何在资源受限时暂停并抢占低优先级的微调作业,从而优先运行高优先级的推理服务器。
运行以下命令,将推理服务器的副本扩容为两个:
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,以便为优先级更高的推理服务器 Deployment 释放资源。
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运行以下命令以显示工作负载对象:
kubectl get workloads --namespace=llm输出类似于以下内容,表明其中一个推理服务器 Deployment 已终止,并且微调作业已被重新接受。
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}