Nanbeige4.1-3B部署案例:Kubernetes集群中以StatefulSet部署3B模型服务
Nanbeige4.1-3B部署案例Kubernetes集群中以StatefulSet部署3B模型服务想不想在Kubernetes集群里像部署一个Web应用那样轻松部署一个3B参数的大语言模型服务今天我就带你走一遍完整的流程用StatefulSet把Nanbeige4.1-3B模型稳稳当当地跑起来。你可能听说过很多大模型部署方案但很多要么太复杂要么不够稳定。特别是对于像Nanbeige4.1-3B这样3B参数规模的模型既要考虑GPU资源的高效利用又要保证服务的稳定性和可扩展性。传统的Deployment部署方式在处理有状态服务时往往力不从心而StatefulSet正好能解决这个问题。这篇文章我会手把手教你从环境准备到服务上线每一步都有详细的代码和说明。即使你对Kubernetes不是特别熟悉跟着做也能顺利完成部署。1. 为什么选择StatefulSet部署模型服务在开始动手之前我们先搞清楚为什么要用StatefulSet而不是更常见的Deployment。1.1 StatefulSet的优势StatefulSet是Kubernetes中专门为有状态应用设计的控制器。对于模型服务来说它有几个关键优势稳定的网络标识每个Pod都有固定的主机名比如nanbeige-0、nanbeige-1重启后也不会变。这意味着你的客户端可以稳定地连接到特定的模型实例。有序的部署和扩缩容Pod会按顺序创建0, 1, 2...按逆序删除。这在模型初始化需要较长时间的场景下特别有用。持久化存储可以绑定PersistentVolumeClaim确保模型文件、配置文件等数据在Pod重启后不会丢失。服务发现通过Headless Service每个Pod都有独立的DNS记录方便做负载均衡或直接访问特定实例。1.2 Nanbeige4.1-3B模型特点Nanbeige4.1-3B是一个3B参数规模的开源语言模型虽然参数不算特别大但部署时仍然需要考虑模型文件大小完整模型文件大约6-8GB加载到显存需要6GB的GPU内存初始化时间从磁盘加载模型到GPU显存需要一定时间通常几十秒到几分钟服务稳定性需要7x24小时稳定运行不能随便重启资源隔离需要独占GPU资源避免与其他服务争抢这些特点使得StatefulSet成为最合适的部署选择。2. 部署前的环境准备在开始部署之前我们需要确保Kubernetes集群已经准备好相应的环境。2.1 集群要求你的Kubernetes集群需要满足以下基本要求Kubernetes版本1.20GPU节点至少有一个节点配备了NVIDIA GPU建议RTX 3090 24GB或更高NVIDIA设备插件已安装nvidia-device-plugin存储类配置了支持ReadWriteMany访问模式的StorageClass如NFS、CephFS镜像仓库可以访问Docker Hub或私有镜像仓库2.2 检查GPU资源首先确认集群中有可用的GPU节点# 查看节点信息 kubectl get nodes -o wide # 查看节点的GPU资源 kubectl describe node node-name | grep -A 10 Capacity你应该能看到类似这样的输出表明节点有GPU资源Capacity: cpu: 16 memory: 64Gi nvidia.com/gpu: 12.3 创建命名空间为模型服务创建一个独立的命名空间方便管理# 创建命名空间 kubectl create namespace nanbeige # 设置为当前上下文 kubectl config set-context --current --namespacenanbeige3. 准备模型文件和Docker镜像部署前需要准备好两样东西模型文件和服务的Docker镜像。3.1 下载模型文件Nanbeige4.1-3B的模型文件可以从Hugging Face下载。我们创建一个PersistentVolume来存储模型文件这样多个Pod可以共享同一份模型数据。首先创建NFS共享目录如果你使用NFS作为后端存储# 在NFS服务器上创建共享目录 sudo mkdir -p /data/nanbeige-model sudo chmod 777 /data/nanbeige-model # 下载模型文件到NFS目录 cd /data/nanbeige-model git lfs install git clone https://huggingface.co/Nanbeige/Nanbeige4.1-3B3.2 创建持久化存储在Kubernetes中创建PersistentVolume和PersistentVolumeClaim# nanbeige-model-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: nanbeige-model-pv namespace: nanbeige spec: capacity: storage: 50Gi accessModes: - ReadWriteMany nfs: server: your-nfs-server-ip path: /data/nanbeige-model storageClassName: --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nanbeige-model-pvc namespace: nanbeige spec: accessModes: - ReadWriteMany resources: requests: storage: 50Gi storageClassName: 应用这个配置kubectl apply -f nanbeige-model-pv.yaml3.3 构建Docker镜像创建一个简单的FastAPI服务来提供模型API# Dockerfile FROM pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime # 安装系统依赖 RUN apt-get update apt-get install -y \ git \ curl \ rm -rf /var/lib/apt/lists/* # 安装Python依赖 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY app.py /app/ COPY start.sh /app/ # 设置工作目录 WORKDIR /app # 暴露端口 EXPOSE 8000 # 启动命令 CMD [bash, start.sh]对应的requirements.txtfastapi0.104.1 uvicorn[standard]0.24.0 transformers4.35.0 torch2.0.1 accelerate0.24.1 pydantic2.5.0应用代码app.pyfrom fastapi import FastAPI, HTTPException from pydantic import BaseModel from transformers import AutoModelForCausalLM, AutoTokenizer import torch import uvicorn from typing import List, Optional app FastAPI(titleNanbeige4.1-3B API) # 模型和分词器全局变量 model None tokenizer None class ChatMessage(BaseModel): role: str content: str class ChatRequest(BaseModel): messages: List[ChatMessage] max_tokens: Optional[int] 512 temperature: Optional[float] 0.6 top_p: Optional[float] 0.95 stream: Optional[bool] False app.on_event(startup) async def load_model(): 启动时加载模型 global model, tokenizer print(正在加载模型...) model_path /data/model/Nanbeige4.1-3B # 加载分词器 tokenizer AutoTokenizer.from_pretrained( model_path, trust_remote_codeTrue ) # 加载模型 model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue ) print(模型加载完成) app.post(/v1/chat/completions) async def chat_completion(request: ChatRequest): 聊天补全接口 if model is None or tokenizer is None: raise HTTPException(status_code503, detail模型未加载完成) try: # 准备输入 input_ids tokenizer.apply_chat_template( [msg.dict() for msg in request.messages], return_tensorspt ).to(model.device) # 生成回复 with torch.no_grad(): outputs model.generate( input_ids, max_new_tokensrequest.max_tokens, temperaturerequest.temperature, top_prequest.top_p, do_sampleTrue ) # 解码输出 response tokenizer.decode( outputs[0][len(input_ids[0]):], skip_special_tokensTrue ) return { choices: [{ message: { role: assistant, content: response } }] } except Exception as e: raise HTTPException(status_code500, detailstr(e)) app.get(/health) async def health_check(): 健康检查接口 return {status: healthy, model_loaded: model is not None} if __name__ __main__: uvicorn.run(app, host0.0.0.0, port8000)启动脚本start.sh#!/bin/bash # 等待模型文件就绪 while [ ! -d /data/model/Nanbeige4.1-3B ]; do echo 等待模型文件... sleep 10 done # 启动服务 python app.py构建并推送镜像# 构建镜像 docker build -t your-registry/nanbeige-api:1.0.0 . # 推送镜像 docker push your-registry/nanbeige-api:1.0.04. 创建StatefulSet部署模型服务现在进入核心部分创建StatefulSet来部署我们的模型服务。4.1 创建Headless Service首先创建一个Headless Service为StatefulSet的每个Pod提供稳定的网络标识# nanbeige-service.yaml apiVersion: v1 kind: Service metadata: name: nanbeige-service namespace: nanbeige labels: app: nanbeige spec: clusterIP: None # Headless Service selector: app: nanbeige ports: - port: 8000 name: http --- apiVersion: v1 kind: Service metadata: name: nanbeige-loadbalancer namespace: nanbeige labels: app: nanbeige spec: type: LoadBalancer selector: app: nanbeige ports: - port: 80 targetPort: 8000 name: http4.2 创建StatefulSet配置这是最关键的配置文件定义了如何部署我们的模型服务# nanbeige-statefulset.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: nanbeige namespace: nanbeige labels: app: nanbeige spec: serviceName: nanbeige-service replicas: 1 # 初始副本数可以根据需要调整 selector: matchLabels: app: nanbeige template: metadata: labels: app: nanbeige spec: # 节点选择器确保Pod调度到有GPU的节点 nodeSelector: accelerator: nvidia-gpu containers: - name: nanbeige-api image: your-registry/nanbeige-api:1.0.0 imagePullPolicy: Always ports: - containerPort: 8000 name: http resources: limits: nvidia.com/gpu: 1 # 申请1个GPU memory: 16Gi cpu: 4 requests: nvidia.com/gpu: 1 memory: 16Gi cpu: 2 env: - name: MODEL_PATH value: /data/model/Nanbeige4.1-3B - name: CUDA_VISIBLE_DEVICES value: 0 # 挂载模型文件 volumeMounts: - name: model-storage mountPath: /data/model readOnly: true # 健康检查 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 120 # 给模型加载留出时间 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 # 生命周期钩子 lifecycle: preStop: exec: command: [/bin/sh, -c, sleep 30] # 优雅终止 # 持久化卷声明模板 volumeClaimTemplates: - metadata: name: model-storage spec: accessModes: [ReadWriteMany] storageClassName: resources: requests: storage: 50Gi4.3 应用配置并验证部署应用所有配置# 应用Service kubectl apply -f nanbeige-service.yaml # 应用StatefulSet kubectl apply -f nanbeige-statefulset.yaml查看部署状态# 查看StatefulSet状态 kubectl get statefulset -n nanbeige # 查看Pod状态 kubectl get pods -n nanbeige -o wide # 查看Pod详情 kubectl describe pod nanbeige-0 -n nanbeige # 查看日志模型加载过程 kubectl logs -f nanbeige-0 -n nanbeige如果一切正常你应该能看到Pod状态变为Running并且在日志中看到模型加载成功的消息。5. 测试模型服务部署完成后我们来测试一下服务是否正常工作。5.1 获取服务访问地址# 查看LoadBalancer的外部IP kubectl get svc nanbeige-loadbalancer -n nanbeige -o wide5.2 测试API接口使用curl测试健康检查接口# 测试健康检查 curl http://EXTERNAL-IP/health应该返回{status: healthy, model_loaded: true}测试聊天接口# 测试聊天功能 curl -X POST http://EXTERNAL-IP/v1/chat/completions \ -H Content-Type: application/json \ -d { messages: [ {role: user, content: 你好请介绍一下你自己} ], max_tokens: 100, temperature: 0.6 }5.3 使用Python客户端测试创建一个简单的Python客户端# test_client.py import requests import json class NanbeigeClient: def __init__(self, base_url): self.base_url base_url def chat(self, messages, max_tokens512, temperature0.6): 发送聊天请求 url f{self.base_url}/v1/chat/completions payload { messages: messages, max_tokens: max_tokens, temperature: temperature } response requests.post(url, jsonpayload) response.raise_for_status() return response.json() def health(self): 健康检查 url f{self.base_url}/health response requests.get(url) return response.json() # 使用示例 if __name__ __main__: # 替换为你的服务地址 client NanbeigeClient(http://EXTERNAL-IP) # 检查服务状态 health client.health() print(f服务状态: {health}) # 测试对话 messages [ {role: user, content: 写一个Python函数计算两个数的最大公约数} ] response client.chat(messages) print(模型回复:) print(response[choices][0][message][content])6. 运维管理与监控部署完成后我们还需要考虑日常的运维管理。6.1 常用运维命令# 扩展副本数水平扩展 kubectl scale statefulset nanbeige --replicas2 -n nanbeige # 查看所有Pod kubectl get pods -n nanbeige -l appnanbeige # 进入Pod容器 kubectl exec -it nanbeige-0 -n nanbeige -- /bin/bash # 查看资源使用情况 kubectl top pod nanbeige-0 -n nanbeige # 重启Pod kubectl delete pod nanbeige-0 -n nanbeige # StatefulSet会自动创建新的Pod6.2 配置HPA自动扩缩容如果流量波动较大可以配置Horizontal Pod Autoscaler# nanbeige-hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nanbeige-hpa namespace: nanbeige spec: scaleTargetRef: apiVersion: apps/v1 kind: StatefulSet name: nanbeige minReplicas: 1 maxReplicas: 3 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 706.3 配置监控告警使用Prometheus监控模型服务# nanbeige-service-monitor.yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: nanbeige-monitor namespace: nanbeige spec: selector: matchLabels: app: nanbeige endpoints: - port: http interval: 30s path: /metrics在FastAPI应用中添加metrics端点# 在app.py中添加 from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST # 定义指标 REQUEST_COUNT Counter(http_requests_total, Total HTTP Requests) REQUEST_LATENCY Histogram(http_request_duration_seconds, HTTP request latency) app.get(/metrics) async def metrics(): Prometheus metrics端点 return Response(generate_latest(), media_typeCONTENT_TYPE_LATEST) app.middleware(http) async def monitor_requests(request: Request, call_next): 监控中间件 start_time time.time() REQUEST_COUNT.inc() response await call_next(request) latency time.time() - start_time REQUEST_LATENCY.observe(latency) return response7. 常见问题与解决方案在实际部署过程中你可能会遇到一些问题。这里列出一些常见问题及其解决方法。7.1 Pod一直处于Pending状态问题现象Pod状态为Pending无法调度。可能原因和解决方案GPU资源不足# 检查节点GPU资源 kubectl describe node node-name | grep -A 5 Allocatable # 如果有多个节点可以添加节点标签进行调度 kubectl label node node-name acceleratornvidia-gpuPVC绑定失败# 检查PVC状态 kubectl get pvc -n nanbeige # 查看PVC详情 kubectl describe pvc nanbeige-model-pvc -n nanbeige7.2 模型加载失败问题现象Pod虽然运行但模型加载失败健康检查不通过。解决方案检查模型文件路径# 进入Pod检查模型文件 kubectl exec -it nanbeige-0 -n nanbeige -- ls -la /data/model/增加初始化等待时间# 在StatefulSet中调整initialDelaySeconds livenessProbe: initialDelaySeconds: 300 # 增加到5分钟 readinessProbe: initialDelaySeconds: 3007.3 服务响应慢或超时问题现象API请求响应慢甚至超时。解决方案调整资源限制resources: limits: nvidia.com/gpu: 1 memory: 32Gi # 增加内存 cpu: 8 # 增加CPU优化模型加载参数# 在app.py中优化模型加载 model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue, low_cpu_mem_usageTrue # 减少CPU内存使用 )8. 总结通过这篇文章我们完整地走了一遍在Kubernetes集群中使用StatefulSet部署Nanbeige4.1-3B模型服务的流程。从环境准备、镜像构建到StatefulSet配置、服务测试再到运维监控每个环节都有详细的代码和说明。8.1 关键要点回顾StatefulSet的优势对于模型服务这种有状态应用StatefulSet提供了稳定的网络标识、有序的部署和持久化存储比Deployment更合适。资源配置要点确保为Pod分配足够的GPU、CPU和内存资源特别是GPU资源需要独占使用。健康检查配置合理设置livenessProbe和readinessProbe的initialDelaySeconds给模型加载留出足够时间。持久化存储使用PersistentVolume共享模型文件避免每个Pod都下载一遍模型。监控运维配置完善的监控和告警确保服务稳定运行。8.2 后续优化建议部署完成后你还可以考虑以下优化性能优化使用vLLM或TGI等推理框架替换简单的Transformers加载可以获得更好的吞吐量。多副本部署根据业务流量适当增加副本数并通过负载均衡分发请求。模型版本管理建立完整的模型版本管理流程支持模型的热更新和回滚。自动扩缩容基于QPS或GPU利用率配置HPA实现资源的弹性伸缩。服务网格集成考虑集成Istio等服务网格实现更精细的流量管理和安全控制。这种部署方式不仅适用于Nanbeige4.1-3B对于其他类似规模的模型也同样适用。希望这个案例能帮助你更好地在Kubernetes环境中部署和管理模型服务。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。