南北阁 Nanbeige 4.1-3B 部署教程:Kubernetes集群中水平扩展多实例负载均衡方案

1. 引言

你是否遇到过这样的情况:一个本地部署的AI对话工具,当用户量稍微大一点,响应就开始变慢,甚至直接卡死?或者,你想让团队里的每个人都能流畅使用,却发现单台服务器的资源根本不够用。

今天,我们就来解决这个问题。我们将把一个原本只能在单机上运行的“南北阁 Nanbeige 4.1-3B”流式对话工具,部署到Kubernetes集群中。这不仅仅是换个地方运行,而是要实现水平扩展负载均衡——简单说,就是让这个工具能像变形金刚一样,根据用户访问量的多少,自动“分身”出多个实例来同时服务,并且把用户的请求智能地分配给最“闲”的那个实例。

通过这篇教程,你将学会如何将一个本地AI应用,改造成一个高可用、可弹性伸缩的云原生服务。无论你是想提升个人项目的服务能力,还是为团队搭建一个稳定的AI对话平台,这套方案都能为你提供清晰的路径。

2. 项目核心与改造目标

在开始动手之前,我们先明确两件事:我们手里有什么,以及我们要把它变成什么样。

2.1 原项目核心特性回顾

我们基于“南北阁 Nanbeige 4.1-3B”这个30亿参数的国产模型,开发了一个轻量级的流式对话工具。它的优点很突出:

  • 轻量化:3B参数,显存占用小,入门级显卡甚至纯CPU都能跑。
  • 体验好:实现了丝滑的逐字流式输出,并且能把模型的“思考过程”漂亮地折叠展示出来,界面也很现代。
  • 本地化:纯本地运行,没有网络依赖,数据安全有保障。

但它的短板也很明显:它只是一个单进程的Streamlit应用。所有用户共享一个实例,无法应对并发请求,也没有故障恢复能力。

2.2 Kubernetes部署的核心目标

我们的改造,就是要用Kubernetes(后面简称K8s)这个“容器编排大师”,来解决上述问题。具体要实现四个目标:

  1. 容器化封装:将整个应用及其依赖环境打包成一个标准的Docker镜像,做到一次构建,随处运行。
  2. 多实例部署:在K8s集群中同时运行多个完全相同的应用副本(Pod),共同提供服务。
  3. 智能负载均衡:创建一个K8s Service,作为统一的访问入口,自动将外部请求分发到后端的多个Pod上。
  4. 弹性伸缩:配置HPA(Horizontal Pod Autoscaler),让Pod的数量能根据CPU或内存的使用率自动增加或减少,从容应对流量高峰与低谷。

完成改造后,你的应用将从一个“单兵作战”的脚本,升级为一个拥有“集团军”的云原生服务。

3. 基础环境与镜像准备

兵马未动,粮草先行。在将应用部署到K8s之前,我们需要先把它“装箱”,并确保K8s集群就绪。

3.1 将Streamlit应用容器化

首先,我们需要为项目创建一个 Dockerfile,这是构建镜像的蓝图。假设你的项目目录结构如下:

nanbeige-chat/
├── app.py          # 主程序,你的Streamlit应用
├── requirements.txt # Python依赖包列表
├── model/          # 存放Nanbeige 4.1-3B模型文件(需自行下载放置)
└── Dockerfile      # 我们将创建这个文件

创建一个内容如下的 Dockerfile

# 使用一个包含CUDA的Python基础镜像,如果只用CPU可换成 python:3.10-slim
FROM nvcr.io/nvidia/pytorch:23.10-py3

WORKDIR /app

# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# 复制应用代码和模型文件
COPY . .

# 暴露Streamlit默认端口
EXPOSE 8501

# 健康检查,确保应用已启动
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8501/_stcore/health || exit 1

# 启动命令,--server.address 很重要,让服务监听所有IP
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]

关键点说明

  • EXPOSE 8501:声明容器内部使用的端口。
  • HEALTHCHECK:K8s会用这个命令来检查Pod是否健康,不健康的Pod不会被分配流量。
  • --server.address=0.0.0.0:这是关键!让Streamlit监听所有网络接口,而不是默认的localhost,这样K8s集群内部才能访问到它。

接下来,构建并推送镜像到你的镜像仓库(以Docker Hub为例):

# 在项目根目录执行
docker build -t yourusername/nanbeige-chat:1.0.0 .

# 登录Docker Hub
docker login

# 推送镜像
docker push yourusername/nanbeige-chat:1.0.0

3.2 Kubernetes集群准备

你需要一个可用的Kubernetes集群。可以是:

  • 本地开发:Minikube, Kind, K3s。
  • 云服务:阿里云ACK,腾讯云TKE,华为云CCE等。
  • 生产环境:建议使用托管K8s服务,省去运维Master节点的麻烦。

确保你的 kubectl 命令行工具已经配置好,能够连接到目标集群。

4. Kubernetes部署实战:从单实例到多实例

现在进入核心环节,我们将通过几个YAML配置文件,一步步把应用部署到K8s。

4.1 第一步:创建Deployment(定义Pod模板)

Deployment是K8s中管理Pod副本的核心对象。我们创建一个 deployment.yaml 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nanbeige-chat-deployment
  labels:
    app: nanbeige-chat
spec:
  replicas: 2  # 初始启动2个Pod副本
  selector:
    matchLabels:
      app: nanbeige-chat
  template:
    metadata:
      labels:
        app: nanbeige-chat
    spec:
      containers:
      - name: nanbeige-chat-container
        image: yourusername/nanbeige-chat:1.0.0  # 替换为你的镜像地址
        ports:
        - containerPort: 8501
        resources:
          requests:
            memory: "8Gi"   # 每个Pod申请的最小内存,根据模型大小调整
            cpu: "2"        # 每个Pod申请的最小CPU核数
          limits:
            memory: "12Gi"  # 每个Pod能使用的最大内存
            cpu: "4"        # 每个Pod能使用的最大CPU核数
        # 如果模型文件通过持久化存储挂载,需要配置volumeMounts
        # volumeMounts:
        # - name: model-storage
        #   mountPath: /app/model
      # 对应地定义存储卷
      # volumes:
      # - name: model-storage
      #   persistentVolumeClaim:
      #     claimName: model-pvc

应用这个配置:

kubectl apply -f deployment.yaml

执行后,K8s会拉取镜像,并创建2个完全相同的Pod。使用 kubectl get pods 可以看到它们的状态。

4.2 第二步:创建Service(实现负载均衡)

Pod的IP地址是不固定的,而且外部无法直接访问。我们需要一个Service作为稳定的访问入口。创建 service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nanbeige-chat-service
spec:
  selector:
    app: nanbeige-chat  # 选择标签为 app: nanbeige-chat 的Pod
  ports:
  - port: 80            # Service对外暴露的端口
    targetPort: 8501    # 转发到Pod的端口(即Streamlit端口)
  type: LoadBalancer    # 类型,集群外访问通常用这个。集群内可用ClusterIP。

应用配置:

kubectl apply -f service.yaml

如果是云服务商的托管K8s,type: LoadBalancer 会自动创建一个云负载均衡器,并分配一个外部IP。使用 kubectl get svc 查看,在 EXTERNAL-IP 栏位等待分配到一个IP后,就可以通过 http://<EXTERNAL-IP> 访问你的应用了。

负载均衡如何工作? Service通过 selector 找到了所有标签匹配的Pod(目前是2个),并建立了一个端点列表。当请求到达Service时,K8s默认使用轮询(Round Robin)算法,将请求依次分发给不同的Pod。这样就实现了最简单的负载均衡。

4.3 第三步:配置HPA(实现自动伸缩)

手动调整 replicas 的数量太麻烦了。HPA可以帮我们自动完成。创建 hpa.yaml

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nanbeige-chat-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nanbeige-chat-deployment  # 指定要伸缩的Deployment
  minReplicas: 1  # 最小副本数
  maxReplicas: 5  # 最大副本数
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # 目标:所有Pod的平均CPU使用率维持在70%
  # 可以同时监控内存
  # - type: Resource
  #   resource:
  #     name: memory
  #     target:
  #       type: Utilization
  #       averageUtilization: 80

应用配置:

kubectl apply -f hpa.yaml

现在,HPA会每隔15秒(默认)检查一次 nanbeige-chat-deployment 下所有Pod的CPU平均使用率。如果超过70%,它就会自动增加Pod的数量(最多到5个);如果低于70%,则会减少Pod的数量(最少到1个)。

5. 方案优势与生产环境考量

通过以上三步,我们已经完成了一个基本的、可水平扩展的部署方案。我们来总结一下它的优势,并看看在生产环境中还需要注意什么。

5.1 本方案的核心优势

  1. 高可用性:多个实例同时运行,即使某个Pod或节点故障,Service会自动将流量切到健康的Pod,服务不中断。
  2. 弹性伸缩:HPA根据负载自动调整实例数量,在流量高峰时保障性能,在低谷时节约资源。
  3. 负载均衡:用户请求被均匀分发,避免单实例过载,提升整体吞吐量和响应速度。
  4. 标准化与可移植性:容器化封装消除了环境差异,可以在任何K8s集群中一键部署。

5.2 生产环境进阶考量

对于严肃的生产环境,你还需要考虑以下几点:

  • 配置与密钥管理:模型的访问密钥、超参数等不应写在代码或镜像里。应使用K8s的 ConfigMapSecret 来管理。
    # 示例:通过环境变量注入配置
    env:
    - name: MODEL_TEMPERATURE
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: temperature
    - name: API_KEY
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: api-key
    
  • 持久化存储:模型文件通常很大,不应打包进镜像。应该使用持久化卷(Persistent Volume)挂载到每个Pod,或者使用初始化容器(Init Container)从对象存储下载。
  • 更精细的监控与日志:集成Prometheus监控HPA的指标,使用Loki或EFK栈收集所有Pod的日志,方便问题排查。
  • 网络与安全:为Service配置Ingress实现域名访问和HTTPS,配置NetworkPolicy控制Pod间的网络流量。
  • 资源限制与服务质量:在Deployment中精确设置 resources.requestslimits,这对于K8s调度和HPA工作至关重要。

6. 总结

我们从单机运行的Streamlit应用出发,完成了一次向云原生架构的跃迁。回顾整个过程:

  1. 容器化:我们编写了 Dockerfile,将应用打包成标准镜像,解决了环境依赖问题。
  2. 多实例化:我们定义了 Deployment,告诉K8s如何创建和管理多个应用副本。
  3. 服务化:我们创建了 Service,提供了稳定的访问入口和内部的负载均衡。
  4. 自动化:我们配置了 HPA,实现了基于资源使用率的自动扩缩容。

这套“Deployment + Service + HPA”的组合拳,是Kubernetes上部署无状态Web应用的经典模式。它不仅适用于本文的AI对话工具,也适用于绝大多数需要高可用和弹性扩展的Web服务。

现在,你的“南北阁 Nanbeige 4.1-3B”对话工具已经具备了服务团队甚至小型产品的能力。你可以通过一个IP地址访问它,而背后是多个实例在默默支撑,并且会根据压力自动调整兵力。接下来,你可以在此基础上,继续探索配置管理、监控日志、CI/CD等更高级的主题,构建更健壮的生产系统。


获取更多AI镜像

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

更多推荐