发布于 2026 年 7 月 16 日 作者:Michael Troutman,LINBIT
本文重点介绍的 CNCF 项目
在内部运行大语言模型 (LLM) 工作负载是团队在采用托管 API 服务之外的几种模式之一。托管 API 服务方便且适合许多工作负载。自托管是某些团队出于成本可预测性(在高请求量下)、更低的延迟控制以及控制数据驻留以满足合同或监管要求等原因而选择的补充方案。混合方法(针对高容量或敏感工作负载在本地运行开源模型,同时针对受益于托管 API 的任务使用托管 API 调用)是结合两者优点的实用中间方案。本文记录了在 Kubernetes 实验室环境中搭建此类自托管推理堆栈的过程。在本例中,我们选择使用 vLLM 进行推理,并使用 LINSTOR® 提供持久化存储。
vLLM 背景
vLLM 是一个高性能的开源大语言模型推理引擎。它专为在集群环境中高效服务大量并发请求而设计。
vLLM 的一个重要特性是它提供了与 OpenAI 兼容的 REST API。任何已经能够与 OpenAI API 通信的工具(LangChain、LlamaIndex 或你自己调用 OpenAI SDK 的代码)只需更改 URL 即可指向自托管的 vLLM 实例。这种兼容性使得前面描述的混合架构成为可行的替代方案。
设置概览
本文中的操作说明使用了一个由 LINSTOR 通过 LINSTOR Container Storage Interface (CSI) 驱动提供持久化存储的 Kubernetes 集群。Kubernetes 是整个堆栈的编排层,存储集成遵循云原生生态系统中通用的标准 CSI。LINSTOR 是一个基于 DRBD® 构建的开源软件定义存储解决方案,可在节点间提供复制块存储。复制存储非常适合存储需要经受 Pod 重启和节点故障的大型模型权重文件。
本博客使用的模型是 meta-llama/Llama-3.2-1B-Instruct,这是 Meta 推出的一个小型但功能强大的模型,已针对遵循用户指令进行微调。该模型仅有 10 亿参数,足够轻量,可在 CPU 上运行(这对于没有专用 GPU 节点的实验室很重要),同时仍可用于测试此设置。
前置条件
在 Kubernetes 中部署任何内容之前,你需要访问模型本身。Meta Llama 模型在 Hugging Face 上是受限的,这意味着你需要在下载前请求访问权限。
- 在 huggingface.co 创建账户。
- 导航至 Llama-3.2-1B-Instruct 模型页面 并提交访问请求。
- 获批后,前往你的 Hugging Face 账户设置,创建一个具有 读取 权限的访问令牌。
- 妥善保管该令牌,因为接下来你将需要它。
你还需要在 Kubernetes 中部署 LINSTOR,以及一个 StorageClass 以便 Kubernetes 工作负载可以请求 PersistentVolumeClaims。开源的 Piraeus Operator 可将 LINSTOR 和 LINSTOR CSI 驱动部署到 Kubernetes 中,并提供了相关设置文档。在下一节中,你将从名为 linstor-csi-lvm-thin-r2 的 LINSTOR StorageClass 创建一个 PersistentVolumeClaim。
部署
部署由三个 Kubernetes 资源组成:用于模型存储的 PersistentVolumeClaim、用于 Hugging Face 令牌的 Secret,以及用于运行推理服务器的 Deployment 和 Service。
创建 PVC 和 Secret
该 PVC 使用 linstor-csi-lvm-thin-r2 存储类,它会跨集群配置一个具有两个副本的精简配置 LVM 卷。这既提供了冗余,又能高效利用磁盘空间,这对于模型权重可能轻松消耗数十 GB 的情况非常重要。
容器的 mountPath 是 /root/.cache/huggingface。这是 vLLM 容器缓存下载的模型权重的位置。通过使用持久卷支持此路径,模型只需从 Hugging Face 下载一次,后续 Pod 重启将完全跳过下载,因为权重将保留在 LINSTOR 提供的持久存储中。
运行以下命令创建 PVC 和 Hugging Face 令牌 Secret:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: vllm-models
spec:
storageClassName: linstor-csi-lvm-thin-r2
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: Secret
metadata:
name: hf-token-secret
type: Opaque
stringData:
token: "REPLACE_WITH_YOUR_TOKEN"
EOF
❗ 重要提示: 在应用此配置前,请将 REPLACE_WITH_YOUR_TOKEN 替换为你的实际 Hugging Face 访问令牌,并根据实际情况修改 StorageClass 名称。
部署 vLLM
运行以下命令部署 vLLM 推理服务器及其服务(改编自 vLLM Kubernetes 部署文档):
VLLM_IMAGE=public.ecr.aws/q9t5s3a7/vllm-cpu-release-repo:latest
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-server
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: vllm
template:
metadata:
labels:
app.kubernetes.io/name: vllm
spec:
containers:
- name: vllm
image: $VLLM_IMAGE
command: ["/bin/sh", "-c"]
args: [
"vllm serve meta-llama/Llama-3.2-1B-Instruct --gpu-memory-utilization 0.80"
]
env:
- name: HF_TOKEN
valueFrom:
secretKeyRef:
name: hf-token-secret
key: token
ports:
- containerPort: 8000
volumeMounts:
- name: llama-storage
mountPath: /root/.cache/huggingface
volumes:
- name: llama-storage
persistentVolumeClaim:
claimName: vllm-models
---
apiVersion: v1
kind: Service
metadata:
name: vllm-server
spec:
selector:
app.kubernetes.io/name: vllm
ports:
- protocol: TCP
port: 8000
targetPort: 8000
type: ClusterIP
EOF
📝 注意: 即使在仅 CPU 的部署中,vLLM 也会使用 --gpu-memory-utilization 标志来控制为处理请求而保留内存的激进程度。如果不使用此标志,vLLM 默认会保留 92% 的可用内存,这在我的测试环境中导致启动失败。将该值设置为 0.80 为引擎成功初始化提供了足够余量。
查看日志
首次启动需要几分钟时间。vLLM 需要从 Hugging Face 下载模型权重(本模型约 2.5GB)并初始化引擎。运行以下命令跟踪日志。
kubectl logs -f deployment/vllm-server
当你看到类似 “INFO: Application startup complete” 的信息时,即可进行测试。
测试部署
从集群内部测试的最简单方法是部署一个临时的 curl Pod。运行以下命令创建一个:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl-client
namespace: default
spec:
containers:
- name: curl
image: curlimages/curl:latest
command: ["sleep", "infinity"]
restartPolicy: Never
EOF
在 Pod 中启动交互式 Shell 环境:
kubectl exec -it curl-client -- sh
然后使用集群内 DNS 名称向 vLLM 服务发送请求:
curl http://vllm-server.default.svc.cluster.local:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Llama-3.2-1B-Instruct",
"messages": [
{"role": "user", "content": "What is the capital of France?"}
]
}'
如果一切正常,你将收到熟悉的 OpenAI 格式响应:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "The capital of France is Paris."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 15,
"completion_tokens": 9,
"total_tokens": 24
}
}
测试完成后,删除 curl Pod:
kubectl delete pod curl-client
暂停部署
如果需要在排查问题时暂停部署而不丢失 PVC 或配置,可将其缩容至零:
kubectl scale deployment vllm-server --replicas=0
💡 提示: 将部署缩容至零可保留 PVC 和缓存的模型权重。重新扩容部署时无需重新下载模型。
使用以下命令恢复:
kubectl scale deployment vllm-server --replicas=1
结论
本实验设置展示了基本模式:一个在 Kubernetes 中运行的自托管 LLM,由 LINSTOR 管理的复制持久存储支持,并通过标准的 OpenAI 兼容 API 访问。将模型权重缓存在 LINSTOR 卷上意味着 Pod 重启速度很快,而基于 DRBD 的复制意味着该卷不是单点故障。
在此基础上,你可以尝试向集群添加 GPU 节点以获得显著更好的性能,或者在自己的私有数据上进一步训练模型,使其更适合你的特定用例。如果你正在构建混合 AI,自然的下一步是引入一个推理路由器,根据成本、延迟或能力要求在本地部署和托管 API 之间分发请求。llm-d 项目 是一个专为 Kubernetes 设计的开源请求路由器,旨在支持此类设置。这些后续步骤是进一步探索的方向,而非本文实验涵盖的配置。
如果你对在 Kubernetes 中运行 vLLM 或任何容器化应用时使用 LINSTOR,或对 LINBIT® 软件在你的环境中的其他用例有疑问,可以加入 LINBIT 社区论坛。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.