在 AKS 上使用 Ray 训练 LLM

本文介绍如何使用 LLaMA-Factory 和分布式 Ray Train 提交一个 RayJob,在 viggo NLG 数据集上微调 Qwen2.5-7B-Instruct。 该作业使用四个工作器,每个工作器配备一个 GPU,从 Azure Blob 存储 中读取训练数据,并上传训练好的 LoRA 适配器供下游推理使用。

Important

AKS 文档和示例中都提到了开源软件。 您部署的软件被排除在 AKS 服务级别协议、有限保修和 Azure 支持之外。 将开源技术与 AKS 一起使用时,请查阅相应社区和项目维护者提供的支持选项来制定计划。

Microsoft 将负责生成我们在 AKS 上部署的开源包。 该责任包括拥有构建、扫描、签名、验证和快速修复流程的完整所有权,并掌控容器镜像中的二进制文件。 如需了解详细信息,请参阅 AKS 漏洞管理AKS 支持范围

先决条件

  • 按照 在 AKS 上为 Ray 和 Kueue 部署基础结构进行部署的基础结构。
  • 按照 为 AKS 上的 Ray 工作负载配置 Kueue 队列 中所述配置的 Kueue 队列。
  • 集群中至少有四个可用的 A100 GPU(此示例使用四个工作节点,每个节点配备一个 GPU)。
  • Viggo 数据集已上传到位于 llm-pipeline/data/ 的 Blob 存储中(由基础设施 Terraform 模块自动完成)。
  • envsubst 已安装(Linux 上为 gettext 软件包,macOS 上为 brew install gettext)。

设置环境变量。

导航到克隆存储库中的 LLM 训练示例并配置所需的环境变量:

cd <path-to-cloned-repo>/AKS/examples/kueue-and-ray-on-aks/3-workloads/llm-training
export AZURE_STORAGE_ACCOUNT_NAME=$(terraform -chdir=../../1-infrastructure/terraform output -raw storage_account_name)
source env.example

注释

如果您配置了团队队列(选项 B),请在运行 export QUEUE_NAME=team-a 之前设置 export QUEUE_NAME=team-bsource env.example。 默认值 QUEUE_NAME=default 仅适用于单队列配置(选项 A)。

提交工作负载

提交分布式训练 RayJob:

./submit.sh

该脚本根据训练脚本创建 ConfigMap,通过 envsubst 将清单模板渲染为包含四个 GPU 工作节点的配置,并应用该清单。 当已配置的队列中有四个 GPU 可用时,Kueue 会接受该作业。

Tip

运行 ./submit.sh --dry-run 以验证呈现的清单,而不将其应用到群集。

监视进度

如果你当前处于新的 shell 中,请先查找并导出作业名称:

export JOB_NAME=$(kubectl -n ray get rayjob --no-headers -o custom-columns=":metadata.name" | grep llm-training)

查看 RayJob 状态和 Kueue 准入情况:

kubectl -n ray get rayjob ${JOB_NAME} -w
kubectl -n ray get workload -w

作业完成时的预期输出:

NAME                      JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME               AGE
llm-training-xxxxxxxxxx   SUCCEEDED    Complete            2026-01-01T00:00:00Z   2026-01-01T00:19:00Z   19m
NAME                                   QUEUE     RESERVED IN     ADMITTED   FINISHED   AGE
rayjob-llm-training-xxxxxxxxxx-xxxxx   default   cluster-queue   True       True       19m

查看 head Pod 的日志尾部:

kubectl -n ray logs -f -l ray.io/cluster=$(kubectl -n ray get rayjob ${JOB_NAME} -o jsonpath='{.status.rayClusterName}') -c ray-head

验证结果

检查 LoRA 适配器的上传情况:

az storage blob list -c llm-pipeline --prefix lora/ \
  --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --auth-mode login -o table

预期输出:

Name                                       Blob Type    Blob Tier    Length    Content Type
-----------------------------------------  -----------  -----------  --------  ------------------------
lora/latest.txt                            BlockBlob    Hot          86        application/octet-stream
lora/<job-name>/rng_state_3.pth            BlockBlob    Hot          14725     application/octet-stream

验证 latest.txt 指针是否已写入(供批量推理示例自动发现使用):

az storage blob download -c llm-pipeline -n lora/latest.txt \
  --account-name ${AZURE_STORAGE_ACCOUNT_NAME} --auth-mode login

预期输出:

azure://llm-pipeline@<storage-account>.blob.core.chinacloudapi.cn/lora/<job-name>

配置参考

Variable 默认 Description
AZURE_STORAGE_ACCOUNT_NAME (必填) 模块 1 中的存储帐户
NUM_WORKERS 4 GPU 工作节点副本(4 个副本,每个副本配 1 个 GPU)
QUEUE_NAME default Kueue LocalQueue 名称
LLM_DATA_CONTAINER llm-pipeline 用于输入数据的 Blob 容器
LLM_LORA_CONTAINER llm-pipeline 用于 LoRA 上传的 Blob 容器
CONFIGMAP_NAME llm-training-scripts 包含训练脚本的 ConfigMap 的名称

清理资源

删除 RayJob 及其 ConfigMap:

kubectl -n ray delete rayjob ${JOB_NAME}
kubectl -n ray delete configmap ${CONFIGMAP_NAME}

后续步骤