Vue 3 + Spring Boot 21 全栈 RAG 项目Docker Compose 容器化部署

全栈 RAG 项目容器化部署全流程技术文档

场景:Java 21 + Spring AI + Vue 3 + Milvus 在阿里云 3.5GB 内存服务器上的极限部署。


1. 核心技术背景与挑战

  • 内存约束:宿主机 3.5GB 内存。需运行 Java、Nginx、Milvus、Etcd、Minio,内存分配必须极其精确。
  • 通信隔离 :Docker 容器内 127.0.0.1 指向容器自身,无法访问宿主机或其他容器,必须通过环境变量注入内网 IP。
  • 流式响应:AI 对话需要 SSE (Server-Sent Events) 支持,Nginx 默认缓存机制会破坏流式打字机效果。

2. 宿主机环境配置 (关键细节)

2.1 环境变量持久化

为了确保后端能连接 Milvus 和 OpenAI,必须在服务器全局配置变量。

  • 操作文件/etc/environment

  • 细节 :不要在变量名前加 export,直接写 KEY="VALUE"

  • 配置内容

    bash 复制代码
    PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
    CLOUD_IP="172.22.229.185" # 阿里云内网IP,通过 hostname -I 获取
    OPENAI_API_KEY="sk-xxxxxxxxxxxx"
  • 生效方法 :执行 source /etc/environment

2.2 内存赤字账本 (优化目标)

组件 内存需求 最终限制 (Docker Limit) 优化手段
Java (Spring AI) ~1.0GB 512MB 虚拟线程 + SerialGC + Xmx256m
Milvus ~1.0GB 1GB 保持单机版最小化运行
Nginx (Vue) ~100MB 不限制 (实际约3MB) Alpine 轻量镜像

3. 前后端容器化方案

3.1 后端:Dockerfile (Java 21 极致版)

避坑细节:使用 JRE 而非 JDK 缩小体积;针对低内存强制使用串行 GC。

dockerfile 复制代码
# 第一阶段:Maven 编译
FROM maven:3.9.6-eclipse-temurin-21-alpine AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests

# 第二阶段:运行
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 核心 JVM 参数细节:
# -Xmx256m: 堆内存留一半给 Metaspace 和线程栈
# -XX:+UseSerialGC: 显著降低内存开销,适合单核/双核云服务器
# -Djdk.virtualThreadScheduler.parallelism=1: 限制虚拟线程并行度
ENTRYPOINT ["java", \
            "-Xmx256m", "-Xms256m", \
            "-XX:MaxMetaspaceSize=128m", \
            "-XX:+UseSerialGC", \
            "-Xss256k", \
            "-XX:+ExitOnOutOfMemoryError", \
            "-Djdk.virtualThreadScheduler.parallelism=1", \
            "-jar", "app.jar"]

3.2 前端:Dockerfile (Vue 3 + Vite)

dockerfile 复制代码
FROM node:20-alpine AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install --registry=https://registry.npmmirror.com
COPY . .
RUN npm run build

FROM nginx:stable-alpine
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

3.3 关键:Nginx 配置 (nginx.conf)

避坑细节

  1. 路径匹配 :如果前端请求 /api/chatlocation 必须是 /api/。若配置为 /ai/ 会导致返回 index.html 源码。
  2. SSE 支持 :必须关闭 proxy_buffering
nginx 复制代码
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        # ai-rag-service 是 docker-compose 中的服务名
        proxy_pass http://ai-rag-service:8081/api/; 
        
        # SSE 流式响应优化
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding on;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

4. 多服务编排 (docker-compose.yml)

yaml 复制代码
version: '3.8'
services:
  ai-rag-service:
    build: 
      context: ../spring-ai-rag
    container_name: ai-rag-backend
    environment:
      - CLOUD_IP=${CLOUD_IP}      # 关键:从宿主机注入内网IP
      - OPENAI_API_KEY=${OPENAI_API_KEY}
    deploy:
      resources:
        limits:
          memory: 512M
    networks:
      - ai-network

  web-ui:
    build: .
    container_name: web-ui-app
    ports:
      - "80:80"
    depends_on:
      - ai-rag-service
    networks:
      - ai-network

networks:
  ai-network:
    driver: bridge

5. 自动化部署脚本 (deploy_all.sh)

避坑细节 :子 Shell 默认不继承 /etc/environment,脚本内必须手动 source

bash 复制代码
#!/bin/bash
set -e

# 1. 强制刷新环境变量
source /etc/environment
echo ">>> 加载 CLOUD_IP: $CLOUD_IP"

# 2. 路径对齐
UI_PATH="/usr/servise/web-ui"
BACKEND_PATH="/usr/servise/spring-ai-rag"

# 3. 代码同步
echo ">>> 正在从 Git 强制对齐源码..."
cd $BACKEND_PATH && git fetch --all && git reset --hard origin/main
cd $UI_PATH && git fetch --all && git reset --hard origin/main

# 4. 重新构建启动
echo ">>> 正在重启 Docker 服务..."
docker compose -f $UI_PATH/docker-compose.yml down
docker compose -f $UI_PATH/docker-compose.yml up -d --build --force-recreate

# 5. 清理碎片
docker image prune -f

echo ">>> 验证服务统计..."
docker stats --no-stream

6. 经典报错与全细节解决方案

Q1: 容器启动瞬间不停重启 (Restarting)

  • 根源 :环境变量 ${CLOUD_IP} 为空,导致 Spring Boot 解析 URI 出现非法字符 $, {
  • 解决 :在 /etc/environment 设置变量并在脚本中执行 source

Q2: 接口返回的是 HTML 源代码 (Vue 首页)

  • 现象 :Network 请求 chat?query=... 返回的是 <!DOCTYPE html>...
  • 根源 :Nginx location 路径匹配失效。比如配置了 /ai/ 转发,前端却请求 /api/。Nginx 找不到匹配,就走 location /try_files 返回了首页。
  • 解决 :确保 Nginx location 路径、前端 baseURL、后端 @RequestMapping 三者路径前缀完全一致。

Q3: 报错 Host name cannot be null or empty

  • 根源 :虽然配置了变量,但 docker rundocker-compose 时没写 -e CLOUD_IP=$CLOUD_IP,变量没传进容器。
  • 验证docker exec ai-rag-backend env | grep CLOUD_IP

Q4: 浏览器显示内容没变 (缓存陷阱)

  • 现象:明明改了代码并重启,浏览器还是报旧错误。
  • 根源 :Headers 显示 200 OK (from disk cache),浏览器没向服务器发请求。
  • 解决 :F12 勾选 Disable cacheCtrl + F5 强制刷新。

Q5: SSE 流式对话卡顿

  • 根源 :Nginx 开启了 proxy_buffering,数据攒够了才发。
  • 解决 :Nginx 配置加入 proxy_buffering off;

7. 统一命令速查手册

7.1 服务监控

  • 查看内存 CPU 实时占用docker stats
  • 查看后端实时日志docker logs -f ai-rag-backend
  • 查看容器最后 100 行日志docker logs --tail 100 ai-rag-backend

7.2 网络验证

  • 容器内验证连通性docker exec -it web-ui-app curl -v http://ai-rag-service:8081/api/chat?query=ping
  • 查看宿主机内网 IPhostname -I
  • 外部测试 SSE 流curl -N "http://8.140.221.150/api/chat?query=hello"

7.3 清理与维护

  • 进入容器内部docker exec -it ai-rag-backend sh
  • 强删冗余容器docker rm -f spring-ai-rag (解决两个后端并存问题)
  • 清理无用镜像docker image prune -f

8. 总结

本方案通过多阶段构建 解决了镜像体积问题,通过串行 GC 与内存限制 解决了低内存服务器的稳定性问题,通过 Nginx 反向代理与环境变量注入解决了前后端连通性与流式响应问题。这是一个完整的生产级单机 AI 部署闭环。


9. 附录:Docker 常用命令生产级大全

在本项目的运维中,熟练掌握以下命令可以解决 90% 的部署与排障问题。

9.1 容器生命周期管理

命令 说明 备注 (针对本项目)
docker ps 查看运行中的容器 检查 ai-rag-backend 是否处于 Up 状态
docker ps -a 查看所有容器(含已停止的) 找回因 OOM 崩溃退出的容器
docker stop <ID/Name> 停止容器 部署新版本前通常需要停止旧容器
docker start <ID/Name> 启动已停止的容器
docker restart <ID/Name> 重启容器 修改了宿主机 /etc/environment 后建议执行
docker rm -f <ID/Name> 强制删除容器 用于清理重名的旧容器(如 spring-ai-rag

9.2 镜像操作 (Image)

命令 说明 备注
docker images 列出本地所有镜像 检查镜像大小,本项目的 Java 镜像应在 160MB 左右
docker build -t <Name>:<Tag> . 构建镜像 后端多阶段构建的核心命令
docker rmi <ImageID> 删除镜像 节省磁盘空间
docker tag <Old> <New> 镜像打标签 方便版本管理,如给时间戳版本打上 latest

9.3 调试与排障 (Debug) ------ 最常用

  • 查看实时日志:

    bash 复制代码
    docker logs -f ai-rag-backend

    -f: 持续追踪;--tail 100: 只看最后 100 行。针对 AI 对话调试必用。

  • 进入容器内部:

    bash 复制代码
    docker exec -it ai-rag-backend sh

    注意:Alpine 镜像通常没有 bash,需使用 sh。进入后可执行 env 查看变量。

  • 查看容器详细配置(JSON):

    bash 复制代码
    docker inspect ai-rag-backend

    用于排查:容器 IP 地址、挂载卷路径、OOM 记录(看 State 里的 OOMKilled)。

  • 从宿主机拷贝文件到容器:

    bash 复制代码
    docker cp /path/to/local/file ai-rag-backend:/app/config/

9.4 状态监控 (Monitor) ------ 内存受限环境必备

  • 实时查看资源占用:

    bash 复制代码
    docker stats

    在进行 AI 提问时观察 MEM %,如果接近 100% 且容器重启,需调大 limit

  • 查看容器内进程:

    bash 复制代码
    docker top ai-rag-backend
  • 查看 Docker 磁盘占用:

    bash 复制代码
    docker system df

9.5 Docker Compose 专项 (编排运维)

/usr/servise/web-ui 目录下执行:

  • 一键启动所有服务(后台): docker compose up -d
  • 强制重新构建并启动: docker compose up -d --build (修改了 Dockerfile 或 Nginx 配置后执行)
  • 停止并删除所有容器与网络: docker compose down
  • 查看编排的服务日志: docker compose logs -f

9.6 系统清理 (Maintenance)

  • 清理所有虚悬镜像(Dangling):

    bash 复制代码
    docker image prune -f

    本项目自动化脚本中已包含,防止多次构建撑爆磁盘。

  • 一键清理无用资源(慎用):

    bash 复制代码
    docker system prune -a

    会删除所有未使用的镜像、容器和网络。


10. 针对本项目的"救急"命令组合

场景 1:后端连不上 Milvus

bash 复制代码
# 1. 确认宿主机变量是否正确
echo $CLOUD_IP 
# 2. 确认变量是否传进容器
docker exec ai-rag-backend env | grep CLOUD_IP
# 3. 确认容器内网络是否通畅
docker exec -it ai-rag-backend ping $CLOUD_IP

场景 2:前端页面能开,但点击对话没反应(接口 502)

bash 复制代码
# 1. 确认后端容器是否存活
docker ps | grep ai-rag-backend
# 2. 如果存活,检查 Nginx 转发逻辑
docker exec -it web-ui-app sh
# 进入后尝试连接后端容器的服务名和端口
curl http://ai-rag-service:8081/api/chat?query=ping

场景 3:服务器内存告急,想优化

bash 复制代码
# 查看哪个组件吃内存最多
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
# 如果是 Java 占用过高且在持续增长,检查 JVM 参数中的 -Xmx 是否生效

11. 总结:生产部署口诀

  1. 改代码 →\rightarrow→ Git Push。
  2. 上服务器 →\rightarrow→ source /etc/environment 刷新变量。
  3. 运行脚本 →\rightarrow→ ./deploy_all.sh 自动化打包重启。
  4. 盯监控 →\rightarrow→ docker stats 观察内存是否稳定。
  5. 看日志 →\rightarrow→ docker logs -f ai-rag-backend 确认 Spring 启动图案出现。

文档结束。 该手册可作为团队内部部署 Spring AI 相关项目的标准指南。

相关推荐
AdMergeX2 小时前
出海行业热点 | Apple推新款“Ultra”高端产品;Google取消30%分成,开放第三方商店;阿里云登陆MWC,支持众多中国企业出海;
阿里云·云计算
Dylan~~~2 小时前
根据测试用例+AI实现界面自动化测试:5大热门工具深度解析
人工智能·测试用例
ezreal_pan2 小时前
Kafka Docker 部署避坑指南:监听器配置与客户端连接问题深度解析
分布式·docker·kafka
水如烟2 小时前
孤能子视角:“人工智能社会学”的元框架
人工智能
Luminbox紫创测控2 小时前
准直光模拟技术:汽车车顶太阳能板辐照测试的应用
人工智能·计算机视觉·汽车
池央2 小时前
在鸿蒙上跑 AI Agent:JiuwenClaw-on-OpenHarmony 完整实战
人工智能·华为·harmonyos
why1512 小时前
AI相关面试题
人工智能·算法
laozhao4322 小时前
浪潮中标沂源县智慧水务平台项目
人工智能·科技·智慧城市
小林攻城狮2 小时前
el-tabs 页签中表格组件宽度闪动问题解决方案
前端·vue.js