通过vLLM部署本地模型并通过Cloudflare Tunnel发布到公网
这份指南将以我本人解决问题的历程为线索,记录每一步的命令、参数、遇到的问题以及相应的解决方案。
1. 准备工作
在开始之前,请确保您具备以下条件:
- 硬件:一台拥有至少24GB显存的NVIDIA GPU。
- 软件:
- 64位的Linux操作系统(例如Ubuntu 20.04+)。
- Python 3.8+ 环境。
pip包管理器。
- 账户与域名:
- 一个 Cloudflare 账户。(若不进行接口的公网开放可以没有)
- 一个您自己的域名,并将其DNS管理设置为使用Cloudflare。(若不进行接口的公网开放可以没有)
2. 部署本地vLLM服务
2.1 安装vLLM
首先,创建一个干净的Python虚拟环境并安装vLLM及其依赖。
1 | # 创建并激活虚拟环境 |
2.2 下载模型文件(离线部署准备)
由于本人的服务器网络环境不佳,我们选择在另一台网络好的电脑上下载模型,再上传到服务器进行离线部署。
1 | # 在一台Windows电脑上尝试使用git clone |
若
git clone命令失败,报错Failed to connect to huggingface.co port 443 after ... ms: Could not connect to server。
原因分析:网络问题,Git无法建立稳定的HTTPS连接。
解决方案:直接从Hugging Face网站手动下载或使用官方库下载。
手动下载:访问模型页面的 “Files and versions“标(以Qwen2.5-VL-7B-Instruct为例),逐个下载所有文件,并将它们全部放在一个新建的文件夹里。
使用
huggingface-hub库下载:编写一个简单的Python脚本来下载,该方法支持断点续传,更稳定。
1
2
3
4
5
6
7 # download_model.py
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="Qwen/Qwen2.5-VL-7B-Instruct",
local_dir="/path/to/save/models/Qwen2.5-VL-7B-Instruct", # 指定本地保存路径
local_dir_use_symlinks=False
)下载完成后,将包含所有模型文件的
Qwen2.5-VL-7B-Instruct文件夹完整上传到你的Linux AI服务器上,例如路径为:/home/models/Qwen2.5-VL-7B-Instruct。
2.3 启动vLLM服务
在模型文件准备就绪后,我们开始启动vLLM服务。
第1轮:基础启动尝试
- 初始指令:
1 | python -m vllm.entrypoints.openai.api_server \ |
问题 #1:GPU显存不足 (预检失败)
- 错误日志:
ValueError: Free memory on device (...) is less than desired GPU memory utilization (0.9, ...)- 问题分析: vLLM默认尝试在第一块显卡(GPU 0)上预留90%的显存,运行命令
nvidia-smi发现,GPU 0 上有多个其他进程占用了约5.7GB显存,导致剩余可用显存不足。- 解决方案: 我们发现服务器的第二块显卡(GPU 1)完全空闲。因此,我们需要明确告诉vLLM去使用这块空闲的GPU。
第2轮:修正显卡选择
我们通过添加 CUDA_VISIBLE_DEVICES 环境变量来指定GPU,让vLLM在空闲的GPU 1上运行。
- 修正后的指令:
1 | CUDA_VISIBLE_DEVICES=1 python -m vllm.entrypoints.openai.api_server |
问题 #2:KV缓存空间不足
- 错误日志:
ValueError: ... GiB KV cache is needed, which is larger than the available KV cache memory ...- 问题分析: 模型加载成功后,vLLM需要为上下文(KV缓存)分配空间。Qwen模型的理论最大长度(128k tokens)非常大,导致计算出的所需KV缓存空间超过了24GB显卡上加载完模型后剩余的空间。
- 解决方案: 使用
--max-model-len参数告诉vLLM,不需要为理论最大长度做准备,只需为一个更实际、更小的长度分配空间即可。
第3轮:解决KV缓存空间问题
我们在命令中加入 --max-model-len 参数,限制上下文长度,使其KV缓存能被装入剩余显存。
- 修正后的指令:
1 | CUDA_VISIBLE_DEVICES=1 python -m vllm.entrypoints.openai.api_server |
问题 ##3:模型名称不匹配 (404 Not Found)
- 错误日志: 服务成功启动,但客户端(
test_client.py)调用时,服务器返回Error: The model 'Qwen/Qwen2.5-VL-7B-Instruct' does not exist.- 问题分析: 当vLLM从本地路径加载模型时,它默认使用完整的文件路径作为模型名。而客户端请求的是模型的Hugging Face官方名称,两者不匹配。
- 解决方案: 使用
--served-model-name参数为本地加载的模型指定一个对外的“别名”,使其与客户端请求的名称一致。同时,既然我们已经在使用一块专用的空闲GPU,我们可以把显存利用率调回到一个较高的值以获得最佳性能。
第5轮:最终成功的命令
成功启动一个稳定、高性能、且能被客户端正确识别的服务。
- 最终指令:
1 | CUDA_VISIBLE_DEVICES=1 python -m vllm.entrypoints.openai.api_server |
- 若多行命令报错,可直接使用以下单行命令
1 | CUDA_VISIBLE_DEVICES=1 python -m vllm.entrypoints.openai.api_server ---model /path/to/models/Qwen2.5-VL-7B-Instruc --served-model-name Qwen/Qwen2.5-VL-7B-Instruct --port 8000 --trust-remote-code --gpu-memory-utilization 0.95 --max-model-len 32768 |
参数详解:
CUDA_VISIBLE_DEVICES=1: 指定程序仅使用编号为1的GPU。--model /path/...: 指定从本地文件夹加载模型,实现离线部署。--served-model-name Qwen/...: 为本地模型设置一个对外服务的别名,以匹配客户端请求。--port 8000: 在8000端口上提供服务。--trust-remote-code: 允许执行模型自带的自定义Python代码,Qwen模型必需。--gpu-memory-utilization 0.95: 设置GPU显存使用率,因为GPU 1是空闲的,可以设置高一些。--max-model-len 32768: 限制最大上下文长度为32k,以解决KV缓存空间不足的问题。
3. 使用Cloudflare Tunnel发布到公网
现在我们有了一个本地运行的服务,接下来将它发布到公网。
3.1 安装cloudflared
添加Cloudflare GPG密钥和软件源
1 | curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloudflare-main.gpg |
安装 cloudflared:
1 | sudo apt update |
3.2 授权cloudflared
1 | cloudflared tunnel login |
3.3 创建并配置隧道
- 创建隧道:
1 | cloudflared tunnel create vllm-service |
记下输出的隧道UUID和凭证文件路径。
2. 创建并编辑配置文件:
1 | mkdir -p /home/path/.cloudflared |
根据你的隧道信息和域名,填入以下内容:
1 | tunnel: <你的隧道UUID> |
- 创建DNS路由:
1 | cloudflared tunnel route dns vllm-service qwen-vl.你的域名 |
3.4 启动隧道服务
临时测试运行
1 | cloudflared tunnel run vllm-service |
作为后台服务永久运行
1 | # 将cloudflared安装为systemd服务 |
4. 如何从公网调用API
现在,您的模型已经成功部署并通过 https://qwen-vl.你的域名 向公网提供服务。任何人都可以通过OPENAI接口进行调用。
1 | # --- 需要提供给用户的信息 --- |