Nanbeige 4.1-3B清爽WebUI部署:Kubernetes集群中水平扩展多实例方案

如果你正在寻找一个既美观又实用的本地大模型对话界面,那么Nanbeige 4.1-3B的Streamlit WebUI绝对值得一试。它拥有现代极简的二次元风格界面,丝滑的流式输出体验,而且只需要一个Python文件就能跑起来。

但是,当你想把这个好用的工具部署到生产环境,或者希望它能同时服务多个用户时,单机部署就显得力不从心了。用户一多,响应就会变慢,甚至可能直接崩溃。这时候,我们就需要更强大的部署方案。

今天,我要分享的就是如何在Kubernetes集群中部署这个WebUI,并且实现水平扩展——也就是说,我们可以根据用户访问量,动态地增加或减少运行实例的数量,确保服务始终稳定、快速。

1. 为什么要在Kubernetes中部署?

你可能会有疑问:这个WebUI不是单文件就能运行吗?为什么还要搞这么复杂的Kubernetes部署?

答案很简单:为了可靠性和可扩展性

想象一下这几个场景:

  • 你的团队成员都想用这个AI助手,但单机版只能一个人用,或者多人用时卡顿明显
  • 白天使用高峰期响应慢,晚上又闲置浪费资源
  • 某天服务器意外重启,服务就中断了,需要手动重新启动
  • 想要升级版本时,不得不停掉服务,影响正在使用的用户

Kubernetes能帮你解决所有这些问题:

  • 自动扩展:用户多了就自动增加实例,少了就减少,节省资源
  • 高可用:一个实例挂了,其他实例还能继续服务
  • 滚动更新:升级版本时无需停机,用户体验不受影响
  • 资源管理:精确控制每个实例用多少CPU和内存
  • 统一管理:所有服务都在一个平台上管理,运维更简单

2. 部署前的准备工作

在开始Kubernetes部署之前,我们需要做好几项准备工作。别担心,我会一步步带你完成。

2.1 环境要求

首先确认你的环境满足以下要求:

  • 一个可用的Kubernetes集群(可以是云厂商的托管服务,也可以是自建的)
  • kubectl命令行工具已安装并配置好
  • Docker环境(用于构建镜像)
  • 模型权重文件(Nanbeige 4.1-3B)

2.2 项目结构改造

原始的app.py是为单机运行设计的,我们需要做一些小调整,让它更适合容器化部署。

创建一个新的项目目录结构:

nanbeige-webui-k8s/
├── Dockerfile          # 容器镜像构建文件
├── app.py              # 修改后的WebUI主程序
├── requirements.txt    # Python依赖包
├── k8s/
│   ├── deployment.yaml    # Kubernetes部署配置
│   ├── service.yaml       # 服务暴露配置
│   └── hpa.yaml           # 自动扩缩容配置
└── config/
    └── model_config.py    # 模型配置管理

2.3 修改app.py支持环境变量

为了让部署更灵活,我们需要修改app.py,让它可以从环境变量读取配置:

import os
import streamlit as st
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
import threading
from transformers import TextIteratorStreamer

# 从环境变量读取配置,如果没有则使用默认值
MODEL_PATH = os.getenv("MODEL_PATH", "/app/models/nanbeige")
DEVICE = os.getenv("DEVICE", "cuda" if torch.cuda.is_available() else "cpu")
MAX_LENGTH = int(os.getenv("MAX_LENGTH", "4096"))
TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))

# 添加健康检查端点(Kubernetes需要)
def health_check():
    """简单的健康检查接口"""
    return {"status": "healthy", "model_loaded": model is not None}

# 原有的WebUI代码保持不变,只是配置改为从环境变量读取
# ... 这里是你原有的app.py代码 ...

这样修改后,我们就可以在部署时通过环境变量来控制模型路径、设备类型等参数了。

3. 构建Docker镜像

接下来,我们需要把应用打包成Docker镜像,这样Kubernetes才能运行它。

3.1 创建Dockerfile

# 使用Python 3.10作为基础镜像
FROM python:3.10-slim

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    gcc \
    g++ \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY app.py .
COPY config/ ./config/

# 创建模型目录
RUN mkdir -p /app/models

# 设置环境变量
ENV MODEL_PATH=/app/models/nanbeige
ENV PYTHONUNBUFFERED=1
ENV STREAMLIT_SERVER_PORT=8501
ENV STREAMLIT_SERVER_ADDRESS=0.0.0.0

# 暴露端口
EXPOSE 8501

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD python -c "import requests; requests.get('http://localhost:8501/_stcore/health')"

# 启动命令
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]

3.2 创建requirements.txt

streamlit==1.28.0
torch==2.1.0
transformers==4.35.0
accelerate==0.24.0
protobuf==3.20.0

3.3 构建和推送镜像

# 构建镜像
docker build -t your-registry/nanbeige-webui:1.0.0 .

# 推送到镜像仓库(如果是私有仓库需要先登录)
docker push your-registry/nanbeige-webui:1.0.0

如果你没有自己的镜像仓库,可以使用Docker Hub或者云厂商提供的容器镜像服务。

4. Kubernetes部署配置

现在到了最核心的部分——创建Kubernetes的配置文件。我会详细解释每个配置的作用。

4.1 创建Deployment(部署)

Deployment是Kubernetes中管理应用副本的核心对象。我们创建一个deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nanbeige-webui
  namespace: default
  labels:
    app: nanbeige-webui
spec:
  # 设置副本数,初始启动2个实例
  replicas: 2
  selector:
    matchLabels:
      app: nanbeige-webui
  template:
    metadata:
      labels:
        app: nanbeige-webui
    spec:
      # 设置节点选择器,确保Pod调度到有GPU的节点(如果有的话)
      nodeSelector:
        accelerator: nvidia-gpu  # 根据你的集群标签调整
      
      containers:
      - name: nanbeige-webui
        image: your-registry/nanbeige-webui:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8501
          name: webui
        env:
        # 环境变量配置
        - name: MODEL_PATH
          value: "/app/models/nanbeige"
        - name: DEVICE
          value: "cuda"  # 如果使用GPU
        - name: MAX_LENGTH
          value: "4096"
        - name: TEMPERATURE
          value: "0.7"
        
        # 资源限制:根据你的模型大小和硬件调整
        resources:
          requests:
            memory: "8Gi"
            cpu: "2"
            nvidia.com/gpu: 1  # 申请1个GPU(如果有)
          limits:
            memory: "16Gi"
            cpu: "4"
            nvidia.com/gpu: 1  # 限制最多使用1个GPU
        
        # 健康检查
        livenessProbe:
          httpGet:
            path: /_stcore/health
            port: 8501
          initialDelaySeconds: 30  # 容器启动后30秒开始检查
          periodSeconds: 10        # 每10秒检查一次
          timeoutSeconds: 5        # 检查超时时间
          failureThreshold: 3      # 连续失败3次认为不健康
        
        readinessProbe:
          httpGet:
            path: /_stcore/health
            port: 8501
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
        
        # 挂载模型文件
        volumeMounts:
        - name: model-volume
          mountPath: /app/models
          readOnly: true
      
      # 数据卷配置
      volumes:
      - name: model-volume
        persistentVolumeClaim:
          claimName: nanbeige-model-pvc  # 需要提前创建PVC

关键配置说明:

  • replicas: 2:初始启动2个实例,可以同时服务多个用户
  • resources:设置CPU、内存和GPU的资源请求和限制,防止单个实例占用过多资源
  • livenessProbereadinessProbe:健康检查,确保只有健康的实例才会接收流量
  • volumeMounts:挂载模型文件,这样每个实例都能访问相同的模型

4.2 创建Service(服务)

Service负责将流量分发到后端的多个Pod实例。创建service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nanbeige-webui-service
  namespace: default
spec:
  selector:
    app: nanbeige-webui
  ports:
  - port: 80           # Service对外暴露的端口
    targetPort: 8501   # 容器内部的端口
    protocol: TCP
    name: http
  type: LoadBalancer   # 如果是云环境,会自动创建负载均衡器
  # 如果是本地集群,可以使用NodePort:
  # type: NodePort
  # nodePort: 30001    # 指定NodePort端口(30000-32767)

Service类型选择:

  • LoadBalancer:云环境推荐,自动创建外部负载均衡器
  • NodePort:本地集群使用,通过节点IP和指定端口访问
  • ClusterIP:只在集群内部访问

4.3 创建HorizontalPodAutoscaler(水平Pod自动扩缩容)

这是实现自动扩展的关键配置。创建hpa.yaml

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nanbeige-webui-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nanbeige-webui
  minReplicas: 2      # 最小实例数
  maxReplicas: 10     # 最大实例数
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # CPU使用率超过70%时开始扩容
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80  # 内存使用率超过80%时开始扩容
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # 缩容稳定窗口300秒
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60   # 扩容稳定窗口60秒
      policies:
      - type: Percent
        value: 100
        periodSeconds: 60

HPA配置说明:

  • minReplicas: 2:最少保持2个实例,即使没有流量
  • maxReplicas: 10:最多扩展到10个实例
  • averageUtilization: 70:当CPU平均使用率超过70%时,自动增加实例
  • stabilizationWindowSeconds:防止频繁扩缩容的稳定窗口

4.4 创建PersistentVolumeClaim(持久化存储声明)

模型文件通常比较大,我们需要持久化存储。创建pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nanbeige-model-pvc
  namespace: default
spec:
  accessModes:
    - ReadOnlyMany  # 多个Pod可以同时读取
  resources:
    requests:
      storage: 20Gi  # 根据模型大小调整
  storageClassName: standard  # 根据你的集群配置调整

5. 部署到Kubernetes集群

所有配置文件准备好后,就可以开始部署了。

5.1 创建命名空间(可选)

kubectl create namespace nanbeige

5.2 部署模型文件

首先需要把模型文件放到持久化存储中。具体方法取决于你的存储方案:

  • 云存储(如AWS S3、Azure Blob、Google Cloud Storage)
  • 网络文件系统(如NFS)
  • 本地存储卷

这里以NFS为例:

# 假设你的模型文件在本地 /data/models/nanbeige
# 1. 将模型文件复制到NFS共享目录
cp -r /data/models/nanbeige /nfs-share/models/

# 2. 创建PersistentVolume(如果存储管理员没有提前创建)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nanbeige-model-pv
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadOnlyMany
  nfs:
    path: /nfs-share/models
    server: nfs-server-ip
  storageClassName: standard
EOF

5.3 按顺序部署所有资源

# 1. 创建持久化存储
kubectl apply -f pvc.yaml

# 2. 创建Deployment
kubectl apply -f deployment.yaml

# 3. 创建Service
kubectl apply -f service.yaml

# 4. 创建HPA(自动扩缩容)
kubectl apply -f hpa.yaml

5.4 检查部署状态

# 查看Pod状态
kubectl get pods -l app=nanbeige-webui

# 查看Service状态
kubectl get service nanbeige-webui-service

# 查看HPA状态
kubectl get hpa nanbeige-webui-hpa

# 查看Pod日志
kubectl logs -f deployment/nanbeige-webui

如果一切正常,你应该能看到2个Pod在运行:

NAME                              READY   STATUS    RESTARTS   AGE
nanbeige-webui-7c6b8d9c76-abcde   1/1     Running   0          2m
nanbeige-webui-7c6b8d9c76-fghij   1/1     Running   0          2m

6. 访问和测试WebUI

部署完成后,我们来测试一下服务是否正常。

6.1 获取访问地址

# 如果是LoadBalancer类型,获取外部IP
kubectl get service nanbeige-webui-service

# 输出类似:
# NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
# nanbeige-webui-service   LoadBalancer   10.96.100.10   203.0.113.100   80:30001/TCP   5m

# 如果是NodePort类型,使用任意节点IP和指定端口
# 例如:http://节点IP:30001

6.2 测试自动扩缩容

我们可以模拟高并发访问,测试HPA是否正常工作:

# 使用hey或ab进行压力测试
# 安装hey(Go语言编写的HTTP压力测试工具)
go install github.com/rakyll/hey@latest

# 对服务进行压力测试
hey -n 1000 -c 50 http://203.0.113.100

# 观察Pod数量变化
kubectl get hpa nanbeige-webui-hpa --watch

你应该能看到HPA的指标变化,当CPU使用率超过70%时,Pod数量会自动增加。

6.3 监控和日志查看

# 查看所有Pod的日志
kubectl logs -l app=nanbeige-webui --tail=50

# 查看特定Pod的详细日志
kubectl logs deployment/nanbeige-webui --follow

# 查看资源使用情况
kubectl top pods -l app=nanbeige-webui

# 查看事件(有助于排查问题)
kubectl get events --sort-by='.lastTimestamp'

7. 高级配置和优化建议

基本的部署完成了,但要让服务在生产环境中运行得更稳定,还需要一些优化。

7.1 使用ConfigMap管理配置

把环境变量移到ConfigMap中,方便管理:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nanbeige-webui-config
data:
  MODEL_PATH: "/app/models/nanbeige"
  DEVICE: "cuda"
  MAX_LENGTH: "4096"
  TEMPERATURE: "0.7"
  STREAMLIT_SERVER_PORT: "8501"

然后在Deployment中引用:

envFrom:
- configMapRef:
    name: nanbeige-webui-config

7.2 添加Ingress支持(如果需要域名访问)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nanbeige-webui-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: ai.example.com  # 你的域名
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nanbeige-webui-service
            port:
              number: 80

7.3 使用GPU共享(提高资源利用率)

如果GPU资源紧张,可以考虑使用GPU共享:

resources:
  limits:
    nvidia.com/gpu: 0.5  # 共享半个GPU

7.4 设置Pod亲和性和反亲和性

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nanbeige-webui
        topologyKey: kubernetes.io/hostname

这个配置会尽量把Pod调度到不同的节点上,提高可用性。

7.5 添加资源配额限制

apiVersion: v1
kind: ResourceQuota
metadata:
  name: nanbeige-quota
spec:
  hard:
    requests.cpu: "8"
    requests.memory: 32Gi
    limits.cpu: "16"
    limits.memory: 64Gi
    requests.nvidia.com/gpu: 2
    limits.nvidia.com/gpu: 4

8. 常见问题排查

部署过程中可能会遇到一些问题,这里列出几个常见的:

8.1 Pod一直处于Pending状态

# 查看Pod详情
kubectl describe pod nanbeige-webui-xxxxx

# 常见原因:
# 1. 资源不足(特别是GPU)
# 2. 节点选择器不匹配
# 3. PVC没有绑定PV

8.2 Pod启动后立即重启

# 查看崩溃前的日志
kubectl logs nanbeige-webui-xxxxx --previous

# 常见原因:
# 1. 模型路径错误
# 2. 内存不足(OOM)
# 3. Python依赖问题

8.3 服务无法访问

# 检查Service是否正确指向Pod
kubectl describe service nanbeige-webui-service

# 检查Pod的端口是否正确
kubectl get pods nanbeige-webui-xxxxx -o jsonpath='{.spec.containers[0].ports}'

# 从集群内部测试
kubectl run test-curl --image=curlimages/curl -it --rm -- curl http://nanbeige-webui-service

8.4 HPA不工作

# 查看HPA详情
kubectl describe hpa nanbeige-webui-hpa

# 检查metrics-server是否安装
kubectl get apiservices | grep metrics

# 如果没有安装,可以安装metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

9. 总结

通过Kubernetes部署Nanbeige 4.1-3B WebUI,我们不仅获得了美观的界面和流畅的对话体验,还得到了企业级的可靠性和可扩展性。让我们回顾一下关键收获:

部署方案的核心优势:

  1. 自动扩缩容:根据用户访问量动态调整实例数量,既保证性能又节省资源
  2. 高可用性:多个实例同时运行,单个实例故障不影响整体服务
  3. 易于管理:所有配置通过YAML文件管理,版本控制、回滚都很方便
  4. 资源隔离:每个实例有独立的资源限制,不会相互影响
  5. 持续服务:支持滚动更新,升级时无需停机

实际部署建议:

  • 如果是小团队内部使用,可以从2-3个副本开始
  • 根据实际硬件资源调整CPU、内存和GPU的请求值
  • 生产环境一定要设置资源限制,防止单个实例占用过多资源
  • 定期查看日志和监控,了解服务运行状况
  • 考虑使用CI/CD流水线自动化部署过程

下一步可以探索的方向:

  • 集成监控告警(Prometheus + Grafana)
  • 添加身份认证和权限控制
  • 实现多模型切换支持
  • 优化GPU内存使用,支持更大的上下文长度
  • 添加对话历史存储和检索功能

这个部署方案不仅适用于Nanbeige模型,稍作修改就可以用于其他支持Streamlit WebUI的大模型。希望这个方案能帮助你更好地在团队或生产环境中使用大模型对话系统。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐