使用 KubeRay 进行管道并行#

本教程提供了分步指南,介绍如何在支持分布式推理的多节点 Kubernetes 集群上配置和部署 vLLM 服务引擎,并结合 KubeRay。它还解释了如何启用管道并行来启动 vLLM 服务引擎。

目录#

  1. 先决条件

  2. 第 1 步:Ray 和 Kuberay 的基本解释

  3. 第 2 步:准备配置文件

  4. 第 3 步:应用配置

  5. 第 4 步:验证部署

先决条件#

步骤 1:Ray 和 KubeRay 的基本解释#

  1. Ray 是一个专为分布式工作负载(如分布式训练和推理)设计的框架。它通过运行多个进程(通常是容器或 Pod)来高效地分发和同步任务。

  2. Ray 将这些进程组织成一个 Ray 集群,该集群由一个主节点和多个工作节点组成。“节点”一词在此处指的是一个逻辑进程,可以部署为容器或 Pod。

  3. KubeRay 是一个 Kubernetes Operator,可简化在 Kubernetes 环境中创建和管理 Ray 集群的过程。没有 KubeRay,设置 Ray 节点需要手动配置。

  4. 使用 KubeRay,您可以轻松地在 Kubernetes 上部署 Ray 集群。这些集群支持 vLLM 的分布式推理,并支持张量并行和管道并行。

步骤 2:准备配置文件#

  1. 找到示例配置文件 tutorials/assets/values-15-a-minimal-pipeline-parallel-example-raycluster.yaml

  2. 打开文件并更新以下字段

    • 在 yaml 文件中,将 hf_token: <YOUR HF TOKEN> 替换为您实际的 Hugging Face token。

values-15-a-minimal-pipeline-parallel-example-raycluster.yaml 中关键项的解释#

  • raySpec:使用 KubeRay 启用管道并行时必需。

  • headNode:指定 KubeRay 主节点的资源要求,必须相应定义。

    • requestCPU:为 KubeRay 主 Pod 请求的 CPU 资源量。

    • requestMemory:为 KubeRay 主 Pod 分配内存。加载模型需要足够的内存。

    • requestGPU:定义为 KubeRay 主 Pod 分配的 GPU 数量。目前,Ray 主节点也必须同时参与张量并行和管道并行。之所以需要这样,是因为 vllm serve ... 命令在 Ray 主节点上执行,而 vLLM 要求运行此命令的 Pod 至少有一个可见的 GPU。

  • name:您的模型部署的唯一标识符。

  • repository:包含模型服务引擎镜像的 Docker 仓库。

  • tag:指定要使用的模型镜像版本。

  • modelURL:指向 Hugging Face 或其他托管服务上模型的 URL。

  • replicaCount:总共的 KubeRay 工作节点 Pod 数量。

  • requestCPU:为每个 KubeRay 工作节点 Pod 请求的 CPU 资源量。

  • requestMemory:为每个 KubeRay 工作节点 Pod 分配内存。加载模型需要足够的内存。

  • requestGPU:指定为每个 KubeRay 工作节点 Pod 分配的 GPU 数量。

  • vllmConfig:包含特定于模型的配置。

    • tensorParallelSize:指定分配给每个工作节点 Pod 的 GPU 数量。此值必须与 requestGPUraySpec.headNode.requestGPU 相同。

    • pipelineParallelSize:指示管道并行的级别。此值必须等于 replicaCount + 1,代表 Ray 集群节点总数,包括主节点和工作节点。

    • 重要提示

      • 所需的 GPU 总数为 pipelineParallelSize × tensorParallelSize

      • 此总数必须与以下各项的总和完全匹配:

        • replicaCount × requestGPU(分配给 Ray 工作节点 Pod 的 GPU 总数),以及

        • raySpec.headNode.requestGPU(分配给 Ray 主节点 Pod 的 GPU 数量)。

      • Ray 主节点的 requestGPU 值必须与每个工作节点的值相同。

      • tensorParallelSize 定义了分配给每个 Ray 节点(包括主节点和工作节点)的 GPU 数量,并且在所有节点之间必须保持一致。

      • pipelineParallelSize 代表 Ray 节点的总数,因此必须设置为 replicaCount + 1(即工作节点数量加上主节点)。

  • shmSize:配置共享内存大小,以确保在张量和管道并行执行期间,进程间通信有足够的内存可用。

  • hf_token:用于向 Hugging Face 模型中心进行身份验证的 Hugging Face token。

示例片段#

在下面的示例中,我们配置了总共两个 Ray 节点,每个节点配备两个 GPU(一个主节点和一个工作节点)来服务 distilgpt2 模型。我们将张量并行大小设置为 2,因为每个节点包含两个 GPU,并将管道并行大小设置为 2,对应于正在使用的两个 Ray 节点。

servingEngineSpec:
  runtimeClassName: ""
  modelSpec:
  - name: "distilgpt2"
    repository: "vllm/vllm-openai"
    tag: "latest"
    modelURL: "distilbert/distilgpt2"

    replicaCount: 1

    requestCPU: 2
    requestMemory: "20Gi"
    requestGPU: 2

    vllmConfig:
      tensorParallelSize: 2
      pipelineParallelSize: 2

    shmSize: "20Gi"

    raySpec:
      headNode:
        requestCPU: 2
        requestMemory: "20Gi"
        requestGPU: 2

    hf_token: <YOUR HF TOKEN>

步骤 3:应用配置#

使用 Helm 部署配置

helm repo add vllm https://vllm-project.github.io/production-stack
helm install vllm vllm/vllm-stack -f tutorials/assets/values-15-a-minimal-pipeline-parallel-example-raycluster.yaml

预期输出

您应该会看到显示 Helm Chart 成功部署的输出。

NAME: vllm
LAST DEPLOYED: Sun May 11 15:10:34 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

步骤 4:验证部署#

  1. 检查 Pod 的状态

    kubectl wait --for=condition=ready pod -l environment=router,release=router --namespace=default --timeout=60s && \
    kubectl get pods
    

    预期输出

    您应该会看到以下 Pod:

    pod/vllm-deployment-router-8666bf6464-v97v8 condition met
    NAME                                          READY   STATUS    RESTARTS   AGE   IP                NODE                       NOMINATED NODE   READINESS GATES
    kuberay-operator-f89ddb644-858bw              1/1     Running   0          12h   192.168.165.203   insudevmachine             <none>           <none>
    vllm-deployment-router-8666bf6464-v97v8       1/1     Running   0          12h   192.168.165.206   insudevmachine             <none>           <none>
    vllm-distilgpt2-raycluster-head-wvqj5         1/1     Running   0          12h   192.168.190.20    instance-20250503-060921   <none>           <none>
    vllm-distilgpt2-raycluster-ray-worker-fdvnh   1/1     Running   0          12h   192.168.165.207   insudevmachine             <none>           <none>
    
    • 在此示例中,production stack 部署在一个由两个节点组成的 Kubernetes 环境中,每个节点配备两个 GPU。

    • Ray 主节点和工作节点被调度在不同的节点上。总共使用了四个 GPU,每个节点贡献两个 GPU。

    • vllm-deployment-router Pod 作为请求路由器,将传入流量导向相应的模型服务 Pod。

    • vllm-distilgpt2-raycluster-head Pod 负责运行主要的 vLLM 命令。

    • vllm-distilgpt2-raycluster-ray-worker-* Pod 服务模型并处理推理请求。

  2. 验证服务是否正确暴露

    kubectl get services
    

    预期输出

    确保同时存在服务引擎和服务路由器的服务。

    NAME                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
    kuberay-operator                      ClusterIP   10.97.0.153      <none>        8080/TCP            13h
    kubernetes                            ClusterIP   10.96.0.1        <none>        443/TCP             13h
    vllm-distilgpt2-engine-service        ClusterIP   10.106.237.111   <none>        80/TCP              12h
    vllm-distilgpt2-raycluster-head-svc   ClusterIP   None             <none>        8000/TCP,8080/TCP   12h
    vllm-router-service                   ClusterIP   10.97.229.184    <none>        80/TCP              12h
    
    • vllm-*-engine-service 暴露了 Ray 集群的主节点。

    • vllm-*-router-service 负责模型服务 Pod 的路由和负载均衡。

  3. 测试健康检查端点

    要验证服务是否正常运行,请执行以下命令:

    kubectl port-forward svc/vllm-router-service 30080:80
    curl https://:30080/v1/models
    

    注意: 端口转发必须在一个单独的 Shell 会话中执行。如果部署配置正确,您应该会收到类似于以下内容的响应:

    {
        "object": "list",
        "data": [
            {
                "id": "distilbert/distilgpt2",
                "object": "model",
                "created": 1747465656,
                "owned_by": "vllm",
                "root": null
            }
        ]
    }
    

    您还可以执行基本的推理测试来验证管道并行是否按预期工作。请使用以下 curl 命令:

    curl -X POST https://:30080/v1/completions \
     -H "Content-Type: application/json" \
     -d '{
       "model": "distilbert/distilgpt2",
       "prompt": "Once upon a time,",
       "max_tokens": 10
     }'
    

    成功的响应应类似于以下输出:

    {
        "id": "cmpl-92c4ceef0f1c42c9bba10da8306bf86c",
        "object": "text_completion",
        "created": 1747465724,
        "model": "distilbert/distilgpt2",
        "choices": [
            {
                "index": 0,
                "text": "? Huh, are you all red?\n\n",
                "logprobs": null,
                "finish_reason": "length",
                "stop_reason": null,
                "prompt_logprobs": null
            }
        ],
        "usage": {
            "prompt_tokens": 5,
            "total_tokens": 15,
            "completion_tokens": 10,
            "prompt_tokens_details": null
        }
    }
    

    您还可以监视每个 Ray 主节点和工作节点 Pod 的 GPU 使用情况。

    kubectl exec -it vllm-distilgpt2-raycluster-head-wvqj5 -- /bin/bash
    root@vllm-distilgpt2-raycluster-head-wvqj5:/vllm-workspace# nvidia-smi
    Sat May 17 00:10:48 2025
    +-----------------------------------------------------------------------------------------+
    | NVIDIA-SMI 550.90.07              Driver Version: 550.90.07      CUDA Version: 12.4     |
    |-----------------------------------------+------------------------+----------------------+
    | GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
    |                                         |                        |               MIG M. |
    |=========================================+========================+======================|
    |   0  NVIDIA L4                      Off |   00000000:00:03.0 Off |                    0 |
    | N/A   76C    P0             35W /   72W |   20313MiB /  23034MiB |      0%      Default |
    |                                         |                        |                  N/A |
    +-----------------------------------------+------------------------+----------------------+
    |   1  NVIDIA L4                      Off |   00000000:00:04.0 Off |                    0 |
    | N/A   70C    P0             33W /   72W |   20305MiB /  23034MiB |      0%      Default |
    |                                         |                        |                  N/A |
    +-----------------------------------------+------------------------+----------------------+
    
    +-----------------------------------------------------------------------------------------+
    | Processes:                                                                              |
    |  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
    |        ID   ID                                                               Usage      |
    |=========================================================================================|
    |    0   N/A  N/A         8      C   /usr/bin/python3                                0MiB |
    |    1   N/A  N/A      1082      C   ray::RayWorkerWrapper                           0MiB |
    +-----------------------------------------------------------------------------------------+
    
    ###########################################################################################
    
    kubectl exec -it vllm-distilgpt2-raycluster-ray-worker-fdvnh -- /bin/bash
    Defaulted container "vllm-ray-worker" out of: vllm-ray-worker, wait-gcs-ready (init)
    root@vllm-distilgpt2-raycluster-ray-worker-fdvnh:/vllm-workspace# nvidia-smi
    Sat May 17 00:12:06 2025
    +-----------------------------------------------------------------------------------------+
    | NVIDIA-SMI 550.90.07              Driver Version: 550.90.07      CUDA Version: 12.4     |
    |-----------------------------------------+------------------------+----------------------+
    | GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
    |                                         |                        |               MIG M. |
    |=========================================+========================+======================|
    |   0  NVIDIA L4                      Off |   00000000:00:03.0 Off |                    0 |
    | N/A   76C    P0             40W /   72W |   20065MiB /  23034MiB |      0%      Default |
    |                                         |                        |                  N/A |
    +-----------------------------------------+------------------------+----------------------+
    |   1  NVIDIA L4                      Off |   00000000:00:04.0 Off |                    0 |
    | N/A   72C    P0             38W /   72W |   20063MiB /  23034MiB |      0%      Default |
    |                                         |                        |                  N/A |
    +-----------------------------------------+------------------------+----------------------+
    
    +-----------------------------------------------------------------------------------------+
    | Processes:                                                                              |
    |  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
    |        ID   ID                                                               Usage      |
    |=========================================================================================|
    |    0   N/A  N/A       243      C   ray::RayWorkerWrapper                           0MiB |
    |    1   N/A  N/A       244      C   ray::RayWorkerWrapper                           0MiB |
    +-----------------------------------------------------------------------------------------+
    

结论#

在本教程中,您使用 KubeRay 在多节点 Kubernetes 环境中配置和部署了 vLLM 服务引擎,并支持跨多个 GPU 的管道并行。此外,您还学习了如何验证部署并监视相关 Pod 以确保其正常运行。有关进一步的自定义和配置选项,请参阅 values.yaml 文件和 Helm Chart 文档。

要使用单个 Helm release 部署 Ray 集群和标准的 Kubernetes 部署,请参阅位于 tutorials/assets/values-15-b-minimal-pipeline-parallel-example-multiple-modelspec.yaml 的示例配置文件。