首页
/ vLLM × SkyPilot:在云与 Kubernetes 上启动并横向扩展多副本 LLM 推理服务

vLLM × SkyPilot:在云与 Kubernetes 上启动并横向扩展多副本 LLM 推理服务

2026-09-04 10:17:13作者:凤尚柏Louis

本文基于 vLLM 官方文档 docs/deployment/frameworks/skypilot.md 编写,讲解如何使用 SkyPilot 这一开源多云框架,将 vLLM 一键部署到云或 Kubernetes 上的单个实例,并通过内置的自动扩缩容、负载均衡与容错能力扩展为多副本服务。读完本文,你将掌握:SkyPilot YAML 任务文件中 resources / envs / setup / run 四段式的完整配置方法、sky launchsky serve up 的实战命令、service 段的 readiness probe 与 replica_policy 自动扩缩容配置,以及如何把 Gradio 聊天界面挂接到服务负载均衡端点上。

一、方案概述

SkyPilot 是一个用于在任意云上运行 LLM 的开源框架。借助它,vLLM 可以在云与 Kubernetes 上以单实例多服务副本两种形态运行与扩展。对于 Llama-3、Mixtral 等各种开源模型,SkyPilot 的示例库中也提供了更多可参考的配置。

vLLM 侧需要说明的核心事实:多副本场景下每个副本都是一个独立运行 vllm serve 的推理服务实例,SkyPilot 负责在其前面做服务发现、负载均衡与健康检查(readiness probe);而单实例场景则只是“在云节点上拉起一个 vLLM API Server + 可选 Gradio Web UI”的经典部署。

二、前置条件

在开始之前需要准备三件事:

  1. 模型访问权限:前往 HuggingFace 上 meta-llama/Meta-Llama-3-8B-Instruct 的模型页面申请访问权限;
  2. 安装 SkyPilot:按 SkyPilot 官方文档完成安装(可安装 nightly 版本);
  3. 确认云或 Kubernetes 已启用sky check 的输出中应能看到已配置好的云账号或 Kubernetes 集群。
pip install skypilot-nightly
sky check

sky check 会检查本地已配置的云凭证(GCP、AWS 等)与 Kubernetes 上下文,未通过的云会在输出中标记为不可用,因此它是部署前的第一道检查。

三、单实例部署:YAML 任务文件逐段解析

单实例部署的核心是一份 SkyPilot YAML 任务文件(下文称为 serving.yaml)。完整配置如下,随后逐段说明:

resources:
  accelerators: {L4, A10g, A10, L40, A40, A100, A100-80GB} # We can use cheaper accelerators for 8B model.
  use_spot: True
  disk_size: 512  # Ensure model checkpoints can fit.
  disk_tier: best
  ports: 8081  # Expose to internet traffic.

envs:
  PYTHONUNBUFFERED: 1
  MODEL_NAME: meta-llama/Meta-Llama-3-8B-Instruct
  HF_TOKEN: <your-huggingface-token>  # Change to your own huggingface token, or use --env to pass.

setup: |
  conda create -n vllm python=3.10 -y
  conda activate vllm

  pip install vllm==0.4.0.post1
  # Install Gradio for web UI.
  pip install gradio openai
  pip install flash-attn==2.5.7

run: |
  conda activate vllm
  echo 'Starting vllm api server...'
  vllm serve $MODEL_NAME \
    --port 8081 \
    --trust-remote-code \
    --tensor-parallel-size $SKYPILOT_NUM_GPUS_PER_NODE \
    2>&1 | tee api_server.log &

  echo 'Waiting for vllm api server to start...'
  while ! `cat api_server.log | grep -q 'Uvicorn running on'`; do sleep 1; done

  echo 'Starting gradio server...'
  git clone https://github.com/vllm-project/vllm.git || true
  python vllm/examples/applications/chatbot/gradio_openai_chatbot_webserver.py \
    -m $MODEL_NAME \
    --port 8811 \
    --model-url http://localhost:8081/v1 \
    --stop-token-ids 128009,128001

3.1 resources:资源选择与成本策略

  • accelerators:给出一个候选加速器集合 {L4, A10g, A10, L40, A40, A100, A100-80GB}。SkyPilot 会在这些加速器中按“可用 + 成本”自动择优——8B 模型用更便宜的 L4/A10 级卡即可,无需默认落到 A100;
  • use_spot: True:允许使用抢占式(spot)实例以降低成本;
  • disk_size: 512:确保模型 checkpoint 能放得下(8B 模型权重加依赖环境需要较大的磁盘);
  • disk_tier: best:选择性能更好的磁盘层级;
  • ports: 8081:把 vLLM API Server 端口暴露到公网流量入口。

3.2 envs:注入环境变量

MODEL_NAME 指定模型、HF_TOKEN 用于从 HuggingFace 拉取受限模型。注意注释提示:token 可以写进 YAML,也可以不在文件里硬编码,而在启动时用 --env 参数传入(后文命令会演示这种方式,避免把凭证留在配置文件里)。

3.3 setup:构建运行环境

setup 段在节点上执行一次性的环境初始化:创建 Python 3.10 的 conda 环境 vllm,安装 vLLM、Gradio(Web UI 用)与 openai SDK,以及 flash-attn。

需要说明的是,文档中固定的是 vllm==0.4.0.post1flash-attn==2.5.7 这一历史组合。在当前仓库中,vLLM 的版本与内核绑定关系已大幅演进,实际部署时建议按你所选 vLLM 版本对应发布的 flash-attn 要求来调整这两行固定版本,而不是照搬旧版本号。

3.4 run:启动 vLLM API Server 并等待就绪

run 段的执行流程是:

  1. vllm serve $MODEL_NAME --port 8081 --trust-remote-code --tensor-parallel-size $SKYPILOT_NUM_GPUS_PER_NODE 以后台方式启动 vLLM API Server,日志同时写入 api_server.log
  2. 轮询日志,直到出现 Uvicorn running on 字样才继续——这是 uvicorn 完成监听的标准启动标志;
  3. 拉起 Gradio 聊天 Web 服务,指向本机 http://localhost:8081/v1

其中几个值得展开的点:

  • --tensor-parallel-size $SKYPILOT_NUM_GPUS_PER_NODESKYPILOT_NUM_GPUS_PER_NODE 是 SkyPilot 注入的环境变量,表示该节点分到的 GPU 数量。这样写的好处是同一份 YAML 无论调度到 1 卡还是多卡实例,张量并行度都会自动匹配。在 vLLM 当前仓库中,该参数定义于 vllm/engine/arg_utils.py--tensor-parallel-size / -tp),--trust-remote-code 同样注册在同一文件(vllm/engine/arg_utils.py),二者都是 vllm serve 的标准参数。
  • stop_token_ids 128009,128001:这是 Llama-3 系列模型的结束消息 token,传给 Gradio 前端以在流式回复中正确截断。从源码看,仓库中的聊天示例 examples/applications/chatbot/gradio_openai_chatbot_webserver.py 会将其解析为整数列表后放入 OpenAI SDK 请求的 extra_body 中(见该文件第 36-47 行的 client.chat.completions.create 调用)。

3.5 启动命令与验证

在候选 GPU(L4、A10g 等)上启动 Llama-3 8B 服务:

HF_TOKEN="your-huggingface-token" sky launch serving.yaml --env HF_TOKEN

--env HF_TOKEN 表示把本地 shell 中该环境变量的值传入任务,而不是使用 YAML 里的占位符。

命令输出中会出现 Gradio 的公共链接(例如最后一行类似),在浏览器打开即可进行文本补全:

(task, pid=7431) Running on public URL: https://<gradio-hash>.gradio.live

这个公共链接正是由示例脚本 examples/applications/chatbot/gradio_openai_chatbot_webserver.pygradio_interface.queue().launch(..., share=True)share=True 参数生成的——Gradio 会自动建立一条到公网的转发隧道,这也是文档无需额外配置反向代理就能“浏览器直接用”的原因。

可选:换 70B 模型并使用更多 GPU。--gpus 覆盖 YAML 中的加速器选择,并用 --env 覆盖 MODEL_NAME

HF_TOKEN="your-huggingface-token" \
  sky launch serving.yaml \
  --gpus A100:8 \
  --env HF_TOKEN \
  --env MODEL_NAME=meta-llama/Meta-Llama-3-70B-Instruct

此时 SKYPILOT_NUM_GPUS_PER_NODE 为 8,vllm serve 会自动以 8 路张量并行运行 70B 模型。

3.6 关于 Gradio 示例脚本路径的一点勘误

文档的 GUI 示例段落中写的是 vllm/examples/applications/api_client/gradio_openai_chatbot_webserver.py,而当前仓库中该脚本实际位于 examples/applications/chatbot/gradio_openai_chatbot_webserver.pygit clone 下来的目录内也需按实际路径调整)。其命令行接口为:

参数 默认值 说明
-m / --model 必填 传给 OpenAI API 的模型名
--model-url http://localhost:8000/v1 vLLM API Server 的 OpenAI 兼容地址
--port 8001 Gradio 服务端口(文档示例用 8811 避免与 API Server 冲突)
--temp 0.8 采样温度
--stop-token-ids 逗号分隔的停止 token ID 列表

四、横向扩展:多副本 + 就绪探针 + 自动扩缩容

SkyPilot 支持把服务扩展到多副本,并内置自动扩缩容、负载均衡与容错。做法是在 YAML 中追加一个 service 段:

service:
  replicas: 2
  # An actual request for readiness probe.
  readiness_probe:
    path: /v1/chat/completions
    post_data:
      model: $MODEL_NAME
      messages:
        - role: user
          content: Hello! What is your name?
      max_completion_tokens: 1

注意 readiness_probe 是一条真实的推理请求:它向 /v1/chat/completions 发送一个 max_completion_tokens: 1 的极简 chat 请求,只有服务真正能跑通推理时才判定副本就绪——比单纯探活 TCP/HTTP 端口更贴近“模型可服务”的语义。

4.1 完整的多副本 YAML

service 段与单实例配置合并(resources / envs / setup 与上文一致,run 段不再后台化、直接前台运行以便 SkyPilot 托管进程生命周期):

service:
  replicas: 2
  # An actual request for readiness probe.
  readiness_probe:
    path: /v1/chat/completions
    post_data:
      model: $MODEL_NAME
      messages:
        - role: user
          content: Hello! What is your name?
          max_completion_tokens: 1

resources:
  accelerators: {L4, A10g, A10, L40, A40, A100, A100-80GB}
  use_spot: True
  disk_size: 512
  disk_tier: best
  ports: 8081  # Expose to internet traffic.

envs:
  PYTHONUNBUFFERED: 1
  MODEL_NAME: meta-llama/Meta-Llama-3-8B-Instruct
  HF_TOKEN: <your-huggingface-token>

setup: |
  conda create -n vllm python=3.10 -y
  conda activate vllm

  pip install vllm==0.4.0.post1
  # Install Gradio for web UI.
  pip install gradio openai
  pip install flash-attn==2.5.7

run: |
  conda activate vllm
  echo 'Starting vllm api server...'
  vllm serve $MODEL_NAME \
    --port 8081 \
    --trust-remote-code \
    --tensor-parallel-size $SKYPILOT_NUM_GPUS_PER_NODE \
    2>&1 | tee api_server.log

4.2 启动、观察与调用

启动多副本服务:

HF_TOKEN="your-huggingface-token" \
  sky serve up -n vllm serving.yaml \
  --env HF_TOKEN

周期性观察服务状态直到 READY:

watch -n10 sky serve status vllm

输出示例:

Services
NAME  VERSION  UPTIME  STATUS  REPLICAS  ENDPOINT
vllm  1        35s     READY   2/2       xx.yy.zz.100:30001

Service Replicas
SERVICE_NAME  ID  VERSION  IP            LAUNCHED     RESOURCES                STATUS  REGION
vllm          1   1        xx.yy.zz.121  18 mins ago  1x GCP([Spot]{'L4': 1})  READY   us-east4
vllm          2   1        xx.yy.zz.245  18 mins ago  1x GCP([Spot]{'L4': 1})  READY   us-east4

可以看到:两个副本各自调度到一个 1×L4 spot 实例,对外则只暴露一个统一端点(xx.yy.zz.100:30001),负载均衡由 SkyPilot 完成。

服务 READY 后,用该端点直接以 OpenAI 兼容 API 调用(注意多副本场景下端点来自 sky serve status --endpoint 8081):

ENDPOINT=$(sky serve status --endpoint 8081 vllm)
curl -L http://$ENDPOINT/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "meta-llama/Meta-Llama-3-8B-Instruct",
    "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "Who are you?"
    }
    ],
    "stop_token_ids": [128009,  128001]
  }'

4.3 自动扩缩容(Autoscaling)

把固定的 replicas 替换为 replica_policy 即可启用基于 QPS 的自动扩缩容:

service:
  replica_policy:
    min_replicas: 2
    max_replicas: 4
    target_qps_per_replica: 2

含义:副本数始终维持在 2~4 之间,当单副本 QPS 超过 2 时触发扩容。结合上文的完整多副本 YAML,service 段最终形如:

service:
  replica_policy:
    min_replicas: 2
    max_replicas: 4
    target_qps_per_replica: 2
  # An actual request for readiness probe.
  readiness_probe:
    path: /v1/chat/completions
    post_data:
      model: $MODEL_NAME
      messages:
        - role: user
          content: Hello! What is your name?
      max_completion_tokens: 1

修改配置后用 sky serve update 热更新服务,用 sky serve down 停止服务:

# 更新服务
HF_TOKEN="your-huggingface-token" sky serve update vllm serving.yaml --env HF_TOKEN

# 停止服务
sky serve down vllm

五、可选:为多副本服务挂接一个 GUI 前端

多副本场景下,也可以另起一个独立的 Gradio 前端:用户请求先到 GUI,GUI 再把请求转发到 SkyPilot 服务的统一端点,从而在各副本间负载均衡。前端本身不需要 GPU,只需 2 个 CPU:

envs:
  MODEL_NAME: meta-llama/Meta-Llama-3-8B-Instruct
  ENDPOINT: x.x.x.x:3031 # Address of the API server running vllm.

resources:
  cpus: 2

setup: |
  conda create -n vllm python=3.10 -y
  conda activate vllm

  # Install Gradio for web UI.
  pip install gradio openai

run: |
  conda activate vllm
  export PATH=$PATH:/sbin

  echo 'Starting gradio server...'
  git clone https://github.com/vllm-project/vllm.git || true
  python vllm/examples/applications/chatbot/gradio_openai_chatbot_webserver.py \
    -m $MODEL_NAME \
    --port 8811 \
    --model-url http://$ENDPOINT/v1 \
    --stop-token-ids 128009,128001 | tee ~/gradio.log

保存为 gui.yaml 后:

  1. 启动聊天 Web UI,并把服务统一端点注入 ENDPOINT

    sky launch \
      -c gui ./gui.yaml \
      --env ENDPOINT=$(sky serve status --endpoint vllm)
    
  2. 在返回的 Gradio 公共链接上访问,例如:

    | INFO | stdout | Running on public URL: https://6141e84201ce0bb4ed.gradio.live
    

这里的 --model-url 指向 $ENDPOINT/v1 而非 localhost,与单实例场景的关键区别正在于此:GUI 与推理副本解耦,请求经 SkyPilot 端点被负载均衡到 2~4 个 vLLM 副本。

六、部署流程小结与源码索引

把两种形态放到一张流程图中:

  • 单实例sky launch serving.yaml → SkyPilot 按 resources 候选集选最省可用 GPU → setup 装环境 → run 拉起 vllm serve(TP 自适应 SKYPILOT_NUM_GPUS_PER_NODE)→ Gradio 前端经 share=True 生成公共链接;
  • 多副本sky serve up → 每个副本独立运行一份 vllm servereadiness_probe 以真实 1-token 推理请求探活 → 统一端点对外负载均衡 → replica_policy 按 QPS 在 min/max 间伸缩 → sky serve update / sky serve down 管理生命周期。

延伸阅读时可直接参考仓库内这些文件:

最后强调适用前提:上述命令与 YAML 以 SkyPilot 的 sky launch / sky serve 子命令集为前提,需要先在本地完成云凭证配置并通过 sky check;示例中的 vLLM/flash-attn 固定版本来自文档编写时点,升级 vLLM 时请同步核对对应的依赖版本组合。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384