资讯动态

K8s 部署 Vue2+SpringBoot2.5+Nacos2.0.3 实战避坑指南

发布时间:2026/10/28 2:51:07 来源:尧图企业网站定制
简介面向需要在阿里云Kubernetes集群上落地前后端分离项目的开发者这份资源提供了一套可参考的完整部署配置组合覆盖Vue2前端、Nginx反向代理、SpringBoot2.5后端与Nacos2.0.3注册配置中心适合已具备容器与K8s基础、希望打通多组件协同部署的中级读者。压缩包共16个文件约34.69MB以8个yaml清单为主涵盖Nacos的StatefulSet、Service、Headless、Ingress及MySQL配置等编排定义另配2个sh部署脚本、2个Dockerfile、1份SQL初始化脚本、1份nginx.conf、1个jar包与1个gz前端产物从镜像构建到服务发布均有对应文件支撑。已有1342人学习下载。读者可据此理解Nacos有状态集群与数据库初始化方式、前后端镜像构建流程及Ingress暴露规则并借助脚本串联各环节减少自行拼装清单的试错成本。1. 从一台能跑通的集群说起这套 Vue2 Nginx SpringBoot2.5 Nacos2.0.3 到底装什么去年帮一个朋友的公司迁移一套老后台前端 Vue2 打包出来的静态资源、中间一层 Nginx 做反向代理、后端 SpringBoot 2.5 打成 jar、注册配置中心用 Nacos 2.0.3本地 docker-compose 跑得好好的一上 K8s 就翻车Pod 起来了但服务发现不通Nacos 客户端一直报连不上 9848 端口。折腾到凌晨才发现是 Nacos 2.x 除了 8848 还要额外暴露 gRPC 端口Service 只映射了主端口。这套组合在国内中小团队里太常见了Vue2 存量项目多、SpringBoot 2.5 稳定、Nacos 2.0.3 又是很多人第一次接触注册中心时选的版本。装不好不是报错就是半死不活这篇就把我从零搭这套环境的完整过程拆开写包括版本怎么选、YAML 怎么配、坏了怎么救。适合正在把这套老技术栈往 K8s 上搬的开发者新手能照着走通熟手能对一下参数取舍。2. 环境准备与版本锁定先把镜像、端口、命名空间定死2.1 集群与基础组件版本对照这套栈对 K8s 版本不算挑剔但组件之间的版本咬合很关键。我一般会先把下面这张表填好再动手避免装到一半发现镜像拉不下来或者 JDK 不兼容。组件版本说明Kubernetes1.22 ~ 1.241.25 之后移除部分旧 API老 YAML 要改容器运行时containerd 1.6Docker 作为运行时在 1.24 后被弃用JDK8 或 11SpringBoot 2.5 两者都支持团队统一即可Nacos2.0.3服务端与客户端版本尽量一致Nginx1.21-alpine前端静态资源 反向代理Node构建期14.xVue2 项目常见构建环境只在 CI 用版本锁定这件事有血泪经验Nacos 2.0.3 的客户端和服务端如果跨大版本注册能成功但配置拉取会偶发失败日志里只给一句config not found很难查。所以服务端镜像、SpringBoot 里的nacos-client依赖、spring-cloud-alibaba版本三者要对齐我一般锁spring-cloud-alibaba 2021.1配nacos-client 2.0.3。2.2 命名空间与端口规划动手前先把命名空间和端口规划清楚后面所有 YAML 都围绕它写。常见做法是按环境分命名空间中间件单独一个。# 创建业务与中间件命名空间隔离 Nacos 和业务 Pod kubectl create namespace app-prod kubectl create namespace middleware # 确认节点可调度、镜像仓库可访问 kubectl get nodes kubectl get ns端口这块是重灾区。Nacos 2.x 需要三个端口8848 是 HTTP 主端口9848 是客户端 gRPC 端口偏移 10009849 是服务端间 gRPC 端口。很多人只映射 8848结果 SpringBoot 启动时注册成功、心跳却走不通。规划时把这三个端口都记下来Service 和容器都要对上。提示如果集群有 NetworkPolicy 或安全组9848/9849 也要放行否则表现为「注册上了但调用超时」。2.3 镜像准备与私有仓库Vue2 前端和 SpringBoot 后端都需要自己构建镜像。前端用多阶段构建Nginx 只留静态文件后端直接基于openjdk:8-jre-slim。构建完推到私有仓库K8s 里用imagePullSecrets拉取。# 前端镜像构建多阶段Node 构建 Nginx 托管 docker build -t registry.local/app/web:v1.0.0 -f Dockerfile.web . docker push registry.local/app/web:v1.0.0 # 后端镜像构建 docker build -t registry.local/app/api:v1.0.0 -f Dockerfile.api . docker push registry.local/app/api:v1.0.0 # 创建拉取凭证 kubectl create secret docker-registry regcred \ --docker-serverregistry.local \ --docker-usernamedeploy \ --docker-password****** \ -n app-prodDockerfile.web里我一般写两段第一段node:14-alpine跑npm install npm run build第二段nginx:1.21-alpine把dist拷进/usr/share/nginx/html。这样镜像小、启动快也避免把 Node 运行时带进生产。后端镜像注意时区-Duser.timezoneAsia/Shanghai不加的话日志时间会差 8 小时排查问题时容易误判。3. 部署 Nacos 2.0.3StatefulSet、持久化与三个端口的坑3.1 Nacos 单机模式的 StatefulSet 写法生产上 Nacos 一般集群部署但很多中小项目先用单机模式跑通再扩。单机模式用 StatefulSet 是为了固定 Pod 名和存储后面扩集群时改动小。核心是环境变量MODEstandalone和持久化挂载。apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos namespace: middleware spec: serviceName: nacos-headless replicas: 1 selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: containers: - name: nacos image: nacos/nacos-server:v2.0.3 env: - name: MODE value: standalone - name: JVM_XMS value: 512m - name: JVM_XMX value: 512m ports: - containerPort: 8848 - containerPort: 9848 - containerPort: 9849 volumeMounts: - name: nacos-data mountPath: /home/nacos/data volumeClaimTemplates: - metadata: name: nacos-data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10GiMODEstandalone是单机模式的关键不设的话容器会按集群模式启动并尝试找其他节点日志里一直刷cluster not ready。JVM_XMS/XMX显式限制堆内存Nacos 默认堆偏大小节点上容易被 OOMKilled。volumeClaimTemplates保证重启后配置数据不丢这点比用 emptyDir 靠谱得多。3.2 Service 必须暴露 9848 和 9849这是整套部署里最容易翻车的一处。Nacos 2.x 客户端在 8848 完成 HTTP 交互后会再连 9848 走 gRPC 长连接。Service 只写 8848客户端就会卡在注册阶段。apiVersion: v1 kind: Service metadata: name: nacos-headless namespace: middleware spec: clusterIP: None selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 - name: client-grpc port: 9848 targetPort: 9848 - name: server-grpc port: 9849 targetPort: 9849clusterIP: None是 headless ServiceStatefulSet 需要它来做稳定的网络标识。三个端口一个都不能少client-grpc对应 9848server-grpc对应 9849。如果业务 Pod 和 Nacos 不在同一命名空间SpringBoot 里配置的server-addr要写全nacos.middleware.svc.cluster.local:8848别只写nacos:8848。3.3 验证 Nacos 是否真正可用Pod 起来不等于 Nacos 可用。我一般分三步验证看日志、看端口、看控制台。# 1. 看启动日志确认 standalone 模式且无报错 kubectl logs -n middleware nacos-0 | grep -i started # 2. 从集群内另一个 Pod 测端口连通性 kubectl run -n middleware nettest --rm -it --imagebusybox -- \ sh -c nc -zv nacos-headless 8848; nc -zv nacos-headless 9848 # 3. 端口转发到本地看控制台 kubectl port-forward -n middleware svc/nacos-headless 8848:8848日志里出现Nacos started successfully in stand alone mode才算启动完成。端口测试两个都要通9848 不通就是 Service 或 NetworkPolicy 的问题。控制台默认账号密码是nacos/nacos能登录进去、能看到配置列表说明服务端没问题。这一步别省后面 SpringBoot 连不上时你会庆幸先验证过。4. 部署 SpringBoot 2.5 与 Vue2配置注入、健康检查与反向代理4.1 SpringBoot 的 ConfigMap 与 Nacos 地址注入后端镜像里不该硬编码 Nacos 地址用 ConfigMap 注入环境变量SpringBoot 通过spring.cloud.nacos.discovery.server-addr读取。这样换环境只改 ConfigMap。apiVersion: v1 kind: ConfigMap metadata: name: api-config namespace: app-prod data: NACOS_ADDR: nacos-headless.middleware.svc.cluster.local:8848 SPRING_PROFILES_ACTIVE: prod# Deployment 片段注入环境变量并配置健康检查 spec: containers: - name: api image: registry.local/app/api:v1.0.0 envFrom: - configMapRef: name: api-config env: - name: JAVA_OPTS value: -Duser.timezoneAsia/Shanghai -Xms512m -Xmx512m readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 60 periodSeconds: 20envFrom把 ConfigMap 里所有键变成环境变量SpringBoot 的 relaxed binding 会自动把NACOS_ADDR映射到对应配置前提是application.yml里写了server-addr: ${NACOS_ADDR}。initialDelaySeconds给 30 秒是因为 SpringBoot 2.5 启动加 Nacos 注册需要时间给太短 readiness 一直失败Pod 永远不 Ready。/actuator/health要确保management.endpoint.health.show-details配好否则探针拿不到明确状态。4.2 Vue2 静态资源与 Nginx 反向代理配置前端镜像里的 Nginx 要干两件事托管 Vue2 的dist静态文件把/api转发到后端 Service。配置用 ConfigMap 挂进去改代理规则不用重新打镜像。server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # Vue2 history 模式找不到文件回退到 index.html location / { try_files $uri $uri/ /index.html; } # 反向代理到后端 Service location /api/ { proxy_pass http://api-svc.app-prod.svc.cluster.local:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 60s; } }try_files那行是 Vue2 history 路由的必备不加的话刷新页面直接 404。proxy_pass末尾的斜杠要注意带斜杠会把/api/前缀去掉再转发后端接口如果本身不带/api前缀就得这么写不带斜杠则原样转发。这个细节踩过坑的人不少配错了表现为后端一直 404 但 Nginx 日志正常。proxy_read_timeout默认 60 秒接口慢的话要调大。4.3 前端 Deployment 与 Service前端相对简单一个 Deployment 加一个 Service副本数按流量给。apiVersion: apps/v1 kind: Deployment metadata: name: web namespace: app-prod spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: imagePullSecrets: - name: regcred containers: - name: web image: registry.local/app/web:v1.0.0 ports: - containerPort: 80 volumeMounts: - name: nginx-conf mountPath: /etc/nginx/conf.d/default.conf subPath: default.conf volumes: - name: nginx-conf configMap: name: web-nginx-confsubPath挂单个文件而不是整个目录避免把镜像里其他 Nginx 配置覆盖掉。imagePullSecrets别忘私有仓库不配这个 Pod 会卡在ImagePullBackOff。副本给 2 是为了滚动更新时不断流单副本更新期间前端会短暂不可用。5. 避坑与排查这套栈最容易翻车的五个地方5.1 现象SpringBoot 注册成功但调用超时原因Nacos 2.x 的 gRPC 端口 9848 没在 Service 暴露或者 NetworkPolicy 拦了。注册走 8848 能成功心跳和订阅走 9848 就断。 解决检查 Service 的 ports 是否包含 9848kubectl exec进业务 Pod 用nc -zv nacos-headless 9848测通。跨命名空间时确认 DNS 全名写对。5.2 现象前端刷新页面 404原因Vue2 用了 history 路由模式Nginx 没配try_files回退直接找/xxx路径找不到文件。 解决location /里加try_files $uri $uri/ /index.html;。如果是 hash 模式则不会出现但 history 模式必须配。5.3 现象Pod 一直 CrashLoopBackOff日志显示 OOMKilled原因Nacos 或 SpringBoot 默认堆内存偏大节点资源不够容器被内核杀掉。 解决显式设JVM_XMS/JVM_XMX或JAVA_OPTS限制堆同时给容器配resources.limits.memory两者要匹配limit 小于堆的话照样被杀。5.4 现象Nacos 控制台能登录但配置列表为空原因没挂持久化Pod 重启后数据丢了或者连到了另一个命名空间的 Nacos 实例。 解决确认volumeClaimTemplates生效kubectl get pvc -n middleware能看到绑定的 PVC。再确认 SpringBoot 的namespace配置和服务端一致默认是public。5.5 现象镜像拉取失败 ImagePullBackOff原因私有仓库凭证没配、Secret 名字写错、或者 Secret 和 Pod 不在同一命名空间。 解决kubectl describe pod看具体报错Secret 必须和 Deployment 同命名空间imagePullSecrets名字要对上。仓库是 HTTP 的话还要配insecure-registries。6. 装完怎么验证跑通一条链路走到底的检查习惯部署完别急着交付我习惯从外到内走一遍完整链路确认每一层都通。先看所有 Pod 状态再逐层测连通性最后走一次真实请求。# 1. 所有 Pod 是否 Running 且 Ready kubectl get pods -n app-prod kubectl get pods -n middleware # 2. 前端 Service 端口转发浏览器访问首页 kubectl port-forward -n app-prod svc/web-svc 8080:80 # 3. 从集群内测后端健康检查 kubectl run -n app-prod curl-test --rm -it --imagecurlimages/curl -- \ curl -s http://api-svc.app-prod.svc.cluster.local:8080/actuator/health # 4. 确认服务已注册到 Nacos kubectl port-forward -n middleware svc/nacos-headless 8848:8848 # 浏览器打开控制台 - 服务管理 - 服务列表看 api 服务是否存在四步都过才算真正跑通。第 3 步返回{status:UP}说明后端健康检查正常第 4 步在 Nacos 控制台能看到服务实例说明注册链路完整。如果第 3 步通但第 4 步看不到问题就在 Nacos 客户端配置或 9848 端口如果第 4 步有但前端调不通问题在 Nginx 的proxy_pass或后端接口路径。还有一个我每次都会做的动作故意删一个后端 Pod看它能不能自动重建并重新注册到 Nacos。这一步能暴露持久化和注册心跳的问题比静态检查管用。从那以后我每次部署这套栈都强制走一遍「删 Pod 看自愈」的流程宁可多花五分钟也不想上线后半夜被叫起来。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑