本文演示如何使用云容器引擎控制台,使用vLLM提交部署DeepSeek-R1 并提供UI交互界面。
背景
本文使用4台机器,每台机器8张L40S(48G显存),共32x48GB GPUs
vLLM 是用于运行大语言模型(LLM)推理和服务的工具,针对推理做了很多优化,提高了模型的运行效率和性能,使得在资源有限的情况下也能高效运行大语言模型,提供了兼容 OpenAI 的 API,支持多机多卡分布式部署。
Open WebUI是一个专为本地大语言模型(LLMs)设计的Web界面,它支持多种大语言模型运行工具,例如Ollama、vLLM等。
准备工作
-
已开通包含GPU/NPU节点的Kubernetes集群。
-
已安装智算套件。
添加GPU节点(若集群已有GPU资源,请忽略)
-
点击云容器引擎控制台左侧【节点】->【节点池】,点击【创建节点池】
在规格中可选择【x86计算】或【弹性裸金属服务器】中的【GPU计算加速型】或【GPU型】,节点池创建成功后,进入节点池列表,扩容节点至期望的节点数量。
网络准备
由于需要联网拉取容器镜像和获取模型文件,故需要集群所在节点能够访问外网,具体配置可参考VPC虚拟私有网络的“管理SNAT规则“
存储准备
由于模型文件通常较大,建议将模型文件提保存在共享存储中,供集群中的节点mount使用,本文以使用ZOS为例演示
首先需要创建能够访问ZOS的凭证,具体可参考“使用ZOS动态存储卷”
kubectl create secret generic oss-secret-test --from-literal=AK='<ZOS accesskey>' --from-literal=SK='<ZOS secreykey>'
接下来创建用于保存模型文件的StrongClass和PVC
通过kube APIServer
创建StorageClass,其中需要在参数中指定
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: models-vllm
parameters:
azpolicy: single-az
csi.storage.k8s.io/node-publish-secret-name: oss-secret-test
csi.storage.k8s.io/node-publish-secret-namespace: default
type: STANDARD
provisioner: zos.csi.cstor.com
reclaimPolicy: Delete
volumeBindingMode: Immediate
创建PVC,关联StorageClass,其中访问模式修改成多机读写ReadWriteMany,storage根据模型大小适当修改
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: models-vllm
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1500Gi
storageClassName: models-vllm
获取模型
本文通过使用git lfs拉取魔乐社区模型(同hugging face),使用vllm运行
启动Job用于拉取模型文件,并保存在ZOS
在控制台中启动如下任务,注意选择期望的命名空间
注意:修改对应的镜像仓库前缀为对应资源池,可在容器镜像控制台查看,如杭州7,则修改{image_repo}为registry-vpc-crs-hangzhou7.cnsp-internal.ctyun.cn
apiVersion: batch/v1
kind: Job
metadata:
name: download-model
labels:
app: download-model
spec:
template:
metadata:
name: download-model
labels:
app: download-model
spec:
containers:
- name: download
image: {image_repo}/icce/git:2.48.1
command:
- bash
- -c
- |
cd /data; git clone ${模型仓库}
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: models-vllm
restartPolicy: OnFailure
等待任务执行完毕(可通过日志查看文件是否成功)
任务执行完毕后,模型文件就保存在ZOS的PV中的,我们会在后面的流程中使用到
运行模型服务
通过vllm运行分布式任务,以1master,3worker为例,每个Pod有8张卡
通过Kube APIServer提交以下yaml文件
注意:修改对应的镜像仓库前缀为对应资源池,可在容器镜像控制台查看,如杭州7,则修改{image_repo}为registry-vpc-crs-hangzhou7.cnsp-internal.ctyun.cn
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-master
spec:
replicas: 1 # master只需要一个副本
selector:
matchLabels:
app: vllm-master
template:
metadata:
labels:
app: vllm-master
spec:
containers:
- name: vllm-master
image: {image_repo}/icce/vllm-openai:v0.7.3
command: ["/bin/bash", "-c", "ray start --block --head --port=6379 & vllm serve /data/DeepSeek-R1-origin --host 0.0.0.0 --port 8000 --trust-remote-code --enable-chunked-prefill --tensor-parallel-size 8 --pipeline-parallel-size 4 --gpu-memory-utilization 0.90 --enforce-eager "]
resources:
requests:
nvidia.com/gpu: "8"
rdma/rdma_shared_device_a: "1"
limits:
nvidia.com/gpu: "8"
rdma/rdma_shared_device_a: "1"
env:
- name: VLLM_HOST_IP
valueFrom:
fieldRef:
fieldPath: status.podIP # 从环境变量获取 Pod IP
- name: NCCL_SHM_DISABLE
value: "1"
volumeMounts:
- mountPath: /data
name: vllm-models
- name: shm
mountPath: /dev/shm
volumes:
- name: vllm-models
persistentVolumeClaim:
claimName: models-vllm
- name: shm
emptyDir:
medium: Memory
sizeLimit: 500Gi
---
apiVersion: v1
kind: Service
metadata:
name: vllm-master-svc
labels:
app: vllm-master
spec:
clusterIP: None # Headless service
selector:
app: vllm-master
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-worker
spec:
replicas: 3 # worker节点数量
selector:
matchLabels:
app: vllm-worker
template:
metadata:
labels:
app: vllm-worker
spec:
containers:
- name: vllm-worker
image: {image_repo}/icce/vllm-openai:v0.7.3
command: ["/bin/bash", "-c", "ray start --block --address=vllm-master-svc:6379"]
resources:
requests:
nvidia.com/gpu: "8"
rdma/rdma_shared_device_a: "1"
limits:
nvidia.com/gpu: "8"
rdma/rdma_shared_device_a: "1"
env:
- name: VLLM_HOST_IP
valueFrom:
fieldRef:
fieldPath: status.podIP # 从环境变量获取 Pod IP
- name: NCCL_SHM_DISABLE
value: "1"
volumeMounts:
- mountPath: /data
name: vllm-models
- name: shm
mountPath: /dev/shm
volumes:
- name: vllm-models
persistentVolumeClaim:
claimName: models-vllm
- name: shm
emptyDir:
medium: Memory
sizeLimit: 500Gi
其中需要注意以下几点:
-
指定使用之前download模型的PVC,并mount到vllm serve后参数指定的启动目录(/data)
-
master数量只有一个,worker节点数量根据模型实际大小和GPU显存大小、数量适当调整
-
master启动参数:确保tensor-parallel-size × pipeline-parallel-size =(master+worker)× 单pod GPU申请数量,通常 tensor-parallel-size 的值为单pod申请卡数 pipeline-parallel-size 为pod数量(即master+worker),其余参数若遇到错误可自行调整
部署OpenWebUI服务
首先创建用于保存OpenWebUI数据的PVC
创建OpenWebUI
注意:由于从官方拉取镜像可能存在失败的情况,可替换镜像为天翼云的容器镜像:registry-vpc-crs-hangzhou7.cnsp-internal.ctyun.cn:443/icce/open-webui:main,其中hangzhou7请根据实际使用的资源池进行替换
apiVersion: apps/v1
kind: Deployment
metadata:
name: open-webui
spec:
replicas: 1
selector:
matchLabels:
app: open-webui
template:
metadata:
labels:
app: open-webui
spec:
containers:
- name: open-webui
image: ghcr.io/open-webui/open-webui:main
env:
- name: OPENAI_API_BASE_URL
value: ${svc_address} #前面启动的vllm master address
- name: ENABLE_OLLAMA_API
value: "false"
ports:
- containerPort: 8080
volumeMounts:
- name: webui-volume
mountPath: /app/backend/data
volumes:
- name: webui-volume
persistentVolumeClaim:
claimName: webui-vllm
其中需要注意以下几点:
-
指定前面用于保存数据之的PVC,并mount到OpenWebUI保存数据的目录(/app/backend/data)
-
OpenWebUI服务默认端口为8080
-
使用环境变量指定后端模型服务的API接口(即vllm后端服务集群内访问方式的信息)
最后,为OpenWebUI创建服务,暴露open-webui的服务
-
创建服务:点击左侧【网络】->【服务】,选择对应命名空间,点击【创建服务】
-
填好后点击右下角【提交】
访问服务
-
在【网络】->【服务】中,找到上一步创建的service外网,在浏览器中访问,按照提示操作
第一次登录需要设置账户/密码