简介这是一套面向K8s运维及全栈开发者的分布式部署资源包聚焦在阿里云环境下将Vue2前端、Nginx反向代理、SpringBoot2.5后端服务与Nacos2.0.3注册中心完整接入Kubernetes集群。资源共16个文件约34.69MB包含8个YAML编排文件、2个Dockerfile、2个Shell部署脚本及SQL初始化脚本等文件类型覆盖编排、构建、部署与数据初始化已有1340人学习下载。其中YAML覆盖Nacos的StatefulSet、Service、Headless、Ingress以及后端应用和前端Ingress等核心对象Shell脚本封装一键部署流程Dockerfile分别为前端Nginx镜像和后端SpringBoot镜像提供构建配置SQL用于初始化Nacos所需数据库。资源包还附带了打包好的dist前端静态文件、nginx.conf配置及可执行JAR包便于直接基于现有镜像或源码改造落地。适合已掌握K8s基础、希望快速搭建微服务网关与注册中心的生产级实践者既能看到整套编排清单也能借此梳理从镜像构建到服务暴露的完整链路。1. 阿里云K8s跑通vue2nginxspringboot2.5nacos2.0.3这套部署方案到底解决了什么把 vue2 前端、Nginx、SpringBoot 2.5 后端、Nacos 2.0.3 注册配置中心全部搬到阿里云 K8sACK上是很多团队从单机/ECS 迁移到容器化时遇到的第一个完整组合。这个标题看起来只是“一堆组件丢进集群”实际上核心要解决三件事前后端镜像怎么构建、服务之间怎么通过 Nacos 发现、Nginx 怎么在 Pod 网络里把请求正确转给后端。最容易卡住的往往不是 K8s 本身而是 SpringBoot 2.5 与 Nacos 2.0.3 的版本兼容、Nacos 2.x 新增的 gRPC 端口、以及 Nginx 反向代理的路径规则。适合正在做前后端分离项目容器化改造、准备上 ACK 的团队参考也适合想从 docker-compose 迁到 K8s 的读者照着一步步搭。2. 先把版本和边界锁死镜像规划、Nacos兼容性与K8s对象分工2.1 两套镜像三种角色vue2产物进Nginx、SpringBoot2.5以jar进JDK镜像部署到 K8s 后所有东西都以镜像为单位调度。这套方案里镜像只有两类但运行角色有三种前端镜像构建过程分两段先拉 Node 镜像把 vue2 源码构建成 dist 静态文件再拉 Nginx 镜像把 dist 复制进 Nginx 的 html 目录。最终镜像里没有任何 Node 进程只有 Nginx 在跑。选择 Nginx 而不是 Node 服务直接托管静态文件是因为 Nginx 处理静态文件开销小、配置反向代理顺手而且 vue 项目的 history 路由需要 try_files 兜底。后端镜像SpringBoot 2.5 项目打成可执行 jar基础镜像用带 JRE 的 OpenJDK 镜像即可。不需要把源码编进镜像只需要 jar、时区、启动参数尽量把启动命令中可能与环境相关的部分用环境变量占位。POD 里三个角色各自独立Nginx 容器只做静态文件服务和反向代理后端容器只跑 SpringBootNacos 是单独的 StatefulSet。有人会把 Nginx 和后端塞进同一个 Pod省一个 Service但这会把前端发布和后端发布耦合在一起滚动更新时要么一起重启要么做复杂判断。我一般建议严格分开代价只是多写一个 Service yaml排障时清爽很多。2.2 SpringBoot 2.5 配 Nacos 2.0.3Spring Cloud Alibaba版本选型决定成败SpringBoot 2.5 本身不会直接跟 Nacos 通信中间隔着 Spring Cloud 和 Spring Cloud Alibaba。Nacos 2.0.3 的客户端与服务端协议是兼容的但 Spring Cloud Alibaba 的版本必须跟 Spring Boot 2.5 匹配否则会出现 jar 冲突、注册成功但心跳报错、配置拉取不到等一堆问题。常见可用组合是 Spring Boot 2.5.x 搭配 Spring Cloud 2020.0.x 系列再搭配 Spring Cloud Alibaba 2021.1 或同期的 2021.0.x 版本。具体到 pom 或 build.gradle 里一般用 BOM 统一管理依赖版本避免自己手动指定每一个组件版本。实际项目中我会用下面的坐标dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2020.0.6/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version2021.1/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这里的 2021.1 是 Spring Cloud Alibaba 的真实版本号对应的 Nacos client 版本是 2.x 系列与服务端 Nacos 2.0.3 能正常握手。逻辑上Spring Cloud BOM 统一管理 OpenFeign、Gateway 等组件版本Spring Cloud Alibaba BOM 统一管理 nacos-discovery、nacos-config、sentinel 等组件版本。两者不能互相覆盖先声明 Spring Cloud 再声明 Alibaba让 Alibaba 的 BOM 后加载。选型时最怕的是网上随便找一段版本号就抄。SpringBoot 2.4 之后Spring Cloud 的版本命名从 Hoxton 变成了年份号很多老博客写的 2.2.x.RELEASE 对应的是 SpringBoot 2.2 或 2.3。如果你的项目是 2.5要确认 Spring Cloud BOM 是 2020.0.x 而不是 Hoxton。我踩过最狠的一次是直接把 2.2.9.RELEASE 塞进 SpringBoot 2.5 项目结果环境起来后 Nacos 注册是“假成功”控制台能看到实例但服务间调用一直超时最后查出来是 RestTemplate 拦截器抛异常被吞了。2.3 K8s资源对象怎么切Deployment、Service、ConfigMap、Ingress各管一段这套方案里涉及的 K8s 资源对象不多但职责一定要分清。Deployment 管副本数和滚动更新Service 管 Pod 间的稳定访问入口ConfigMap 管 Nginx 配置这类不常变的内容Ingress 负责把集群外部的请求引到前端 Service。用一个表格来看更直观资源对象作用在这套方案里的具体对应Deployment管理无状态应用副本和更新策略前端 Nginx、后端 SpringBootStatefulSet管理有状态应用Pod 名称有序且稳定Nacos 2.0.3Service提供稳定的集群内 DNS 名称nacos-headless、demo-backendConfigMap挂载配置文件Nginx 的 default.confIngress外部流量入口将域名 / 路径转发到前端 Service有一个边界很多人会忽略Nacos 不建议用 Deployment 默认的随机 Pod 名。Nacos 集群模式下节点间需要互相识别用 StatefulSet 可以得到固定的 Pod 名如 nacos-0配合 headless Service 做 DNS 解析。即使是单机模式我实际部署也坚持用 StatefulSet因为以后从单机扩成三节点时不需要改 Service 和配置只需要改 replicas。ConfigMap 的挂载方式要选好。Nginx 配置挂载成文件比把配置写死在镜像里灵活得多。改配置只需要 apply ConfigMap 再滚动重启。SpringBoot 的配置不推荐全部塞进 ConfigMap配置文件里如果有数据库密码、Nacos 密码放 ConfigMap 等于明文存储在 etcd 里建议敏感信息用 K8s Secret非敏感配置再用 ConfigMap。3. 在阿里云K8s里把Nacos2.0.3立起来StatefulSetMySQL最小组件3.1 Nacos 2.0.3的启动条件为什么单机模式也必须接MySQLNacos 默认支持两种存储内嵌 Derby 和外部 MySQL。很多人本地启动时直接用 Derby到了 K8s 上也图省事不加 MySQL结果 Pod 一重启命名空间、配置、用户全部丢了服务注册列表也只剩重启后的新数据。Derby 适合下载下来体验功能不适合任何需要持久化的环境。Nacos 2.0.3 启动时会自动检查环境变量里的数据源配置如果没有 MySQL 配置就落到 Derby。在 K8s 里跑最稳妥的方式是单独部署一个 MySQL或者复用已有的 MySQL 实例然后给 Nacos 建独立数据库。注意不要跟业务库混在一起Nacos 的配置表和用户表有自己的表结构误删或迁移会影响整个微服务体系的配置。另一个关键点是 Nacos 2.0.x 对比 1.x 引入了 gRPC 通信端口从 8848 扩展出 9848 和 9849。容器镜像里需要同时暴露这几个端口K8s Service 也要把这些端口映射出来少一个都会出现服务注册上了但客户端长连接失败的问题。后面坑章节会展开讲。3.2 建MySQL配置库与账号一条SQL把库、账号、权限一次给齐先准备 MySQL。假设集群里已经有一个 MySQL 服务或者使用阿里云 RDS MySQL下面这条 SQL 是常规初始化动作CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nacos% IDENTIFIED BY Nacos123; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; FLUSH PRIVILEGES; USE nacos_config; SOURCE /path/to/nacos-mysql.sql;SQL 的逻辑分三段第一行建库指定 utf8mb4避免配置内容里有表情字符导致写入报错第二行建账号并限定只能访问 nacos_config 库不要给 Nacos 用 root最后一行导入 Nacos 的表结构。nacos-mysql.sql 文件在 Nacos 安装包的 conf 目录里镜像里也有本地解压 Nacos server 就可以拿到不需要额外下载。参数说明MYSQL_SERVICE_DB_NAME 指数据库名也就是这里建的 nacos_configMYSQL_SERVICE_USER 和 MYSQL_SERVICE_PASSWORD 对应刚建的 nacos 账号。密码尽量用大小写字母和数字组合纯数字密码在一些环境变量传递场景下会被解析成数字类型导致连接串拼接出错。3.3 nacos-headlessStatefulSet yaml与Service定义含9848端口这是整套部署里比较核心的一步。直接贴一份可用的 yamlapiVersion: v1 kind: Service metadata: name: nacos-headless namespace: demo labels: app: nacos spec: type: ClusterIP clusterIP: None ports: - name: http port: 8848 targetPort: 8848 - name: grpc port: 9848 targetPort: 9848 selector: app: nacos --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos namespace: demo 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 ports: - containerPort: 8848 - containerPort: 9848 env: - name: MODE value: standalone - name: SPRING_DATASOURCE_PLATFORM value: mysql - name: MYSQL_SERVICE_HOST value: mysql-service - name: MYSQL_SERVICE_PORT value: 3306 - name: MYSQL_SERVICE_DB_NAME value: nacos_config - name: MYSQL_SERVICE_USER value: nacos - name: MYSQL_SERVICE_PASSWORD value: Nacos123这段 yaml 有两个设计点值得说。Service 用了 clusterIP: None即 headless ServiceDNS 会直接返回 Pod 的 IP 而不是虚拟 IP客户端可以通过 nacos-0.nacos-headless.demo.svc.cluster.local 这样的域名直连具体 Pod。Nacos 集群节点间通信依赖这个机制。端口方面http 是 8848grpc 是 9848。注意 Nacos 2.0.3 的 gRPC 端口不是自己配置的而是 8848 主端口加 1000 得到的所以写 9848。如果未来把主端口改成别的gRPC 端口也要同步调整。MODE 设置为 standalone单机模式不需要走 raft 选主如果后面要扩集群改成 cluster 并在 env 里追加 NACOS_SERVERS 指向其他节点地址。3.4 开鉴权与命名空间避免Nacos控制台裸奔Nacos 部署好之后默认控制台地址是 /nacos默认账号密码是 nacos/nacos。这个默认状态在公网环境下非常危险网上能搜到大量 Nacos 未授权访问的漏洞案例本质就是用户没改密码、没开鉴权、默认命名空间直接暴露。2.0.3 开启鉴权需要额外设置环境变量。注意只设 NACOS_AUTH_ENABLEtrue 还不够必须同时设置 NACOS_AUTH_TOKEN而且这个 token 有长度要求一般需要 Base64 编码且超过 32 字节。启动后控制台会要求登录服务发现和配置中心的客户端也要在配置里带上用户名密码。命名空间建议按环境拆开。开发、测试、生产共用一套 Nacos 但用不同命名空间可以避免配置互相覆盖。命名空间用自定义 ID 而不是自动生成的 UUID之后在 SpringBoot 配置文件里写 namespace 时更直观。阿里云 ACK 集群如果是内网部署Nacos 控制台不需要暴露公网用 kubectl port-forward 来访问就行后面第 6 章会写具体命令。4. 前端与后端镜像化落地Dockerfile、Nginx反向代理与K8s部署yaml4.1 vue2多阶段Dockerfile用Node构建层用Nginx运行层前端的 Dockerfile 是最容易写多的一类。有人直接基于 node 镜像把 vue 跑起来有人只 COPY dist 到一个空镜像里结果没有 web 服务器。正确的做法是多阶段构建构建阶段用 Node运行阶段用 Nginx最终镜像体积能控制在 50MB 以内。FROM node:16-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm install --registryhttps://registry.npmmirror.com COPY . . RUN npm run build FROM nginx:1.24-alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx/default.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD [nginx, -g, daemon off;]多阶段构建的意义是最终镜像里没有 node_modules、没有源码只有 Nginx 和 dist。构建阶段单独 COPY package.json 再执行 npm install是为了利用 Docker 的缓存层只要依赖文件没变这一层就不会重新执行后端发版会快很多。npm install 后面加了 npmmirror 镜像源是为了在 ACK 构建时减少从默认源拉依赖的超时概率。这里有个细节npm install 用的是 package-lock.json 锁定版本。vue2 项目如果团队里有人手动改了 node_modules 再提交package-lock 可能会跟 package.json 不同步构建时不是报错就是装出来的版本不一致。遇到这种情况把 lock 文件删掉重新生成一次再提交比在镜像里反复试要省时间。4.2 nginx的default.confhistory路由兜底与/api反向代理Nginx 配置是前端容器里最需要小心的文件直接决定 vue 项目刷新会不会 404、接口请求能不能到后端。下面这份配置经过生产验证server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://demo-backend: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; } }location / 里面的 try_files 是 vue2 history 路由模式的关键。vue-router 默认是 hash 模式地址栏带 #不需要服务端配合。如果用了 history 模式刷新 /order 时 Nginx 会在 html 目录里找 order 文件找不着就 404try_files $uri $uri/ /index.html 的意思是找不到文件就回退到 index.html由 vue-router 接管路由。location /api/ 这一段要重点说明 proxy_pass 的斜杠问题。现在写的 proxy_pass http://demo-backend:8080; 末尾没有斜杠效果是把完整的 /api/xxx 原样转发给后端。如果写成 http://demo-backend:8080/; 那 /api/ 会被吃掉后端收到的是 /xxx。两种写法对应不同的后端接口设计后端的 controller 如果定义的是 /api/user就用不带斜杠的如果定义的是 /user就用带斜杠的。这是一个让人反复翻车的点建议上线前用 curl 直接打一下后端 Service 验证。4.3 SpringBoot 2.5的bootstrap.ymlNacos地址、命名空间与配置动态刷新SpringBoot 2.5 接 Nacos 需要在 pom 里加两个依赖nacos-discovery 和 nacos-config。Spring Cloud 从 2020.0 版本开始默认不再加载 bootstrap.yml所以要额外引入 spring-cloud-starter-bootstrap否则写了 bootstrap.yml 也不会被执行。这是很多人配置了半天 Nacos 一直不生效的第一原因。dependencies dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-bootstrap/artifactId /dependency /dependencies对应的 bootstrap.ymlspring: application: name: demo-backend cloud: nacos: server-addr: nacos-headless:8848 username: nacos password: Nacos123 discovery: namespace: demo-dev config: namespace: demo-dev file-extension: yaml group: DEFAULT_GROUPserver-addr 写的是 nacos-headless:8848这是 K8s 集群内的 Service 名称后端 Pod 不需要知道 Nacos 的公网 IP直接走集群 DNS 解析。namespace 用的是自定义 ID demo-dev对应的命名空间在 Nacos 控制台里手动创建。file-extension 为 yaml表示 Nacos 配置中心里找 dataId 为 demo-backend.yaml 的配置这是默认规则dataId spring.application.name 文件扩展名。动态刷新的原理是 Nacos 客户端会维持长轮询配置变更后服务端推送给客户端。但配置读到 Spring 的 Environment 后Bean 属性不会自动更新必须在需要动态刷新的类上标注 RefreshScope。很多项目把刷新不生效归咎于 Nacos其实 Nacos 侧已经推送了代码里没加注解导致值还是旧的。4.4 后端与前端Deployment yaml探针、资源配额、服务发现后端和前端各自是一个 Deployment 加一个 Service。后端还要配合 readinessProbe否则滚动更新时新 Pod 还没注册到 Nacos流量已经切过去会出现一段时间内 500。apiVersion: apps/v1 kind: Deployment metadata: name: demo-backend namespace: demo spec: replicas: 2 selector: matchLabels: app: demo-backend template: metadata: labels: app: demo-backend spec: containers: - name: demo-backend image: registry.cn-hangzhou.aliyuncs.com/demo/backend:20240501 ports: - containerPort: 8080 env: - name: NACOS_ADDR value: nacos-headless:8848 - name: TZ value: Asia/Shanghai readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 40 periodSeconds: 10 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1 memory: 1Gi --- apiVersion: v1 kind: Service metadata: name: demo-backend namespace: demo spec: selector: app: demo-backend ports: - port: 8080 targetPort: 8080readinessProbe 的路径 /actuator/health 需要后端引入 spring-boot-starter-actuator在 pom 里加依赖就行。这个健康检查的返回值会决定 Pod 是否被 Endpoint 控制器加入 Service 后端列表比单纯的 TCP 检查可靠因为 TCP 通不代表 SpringBoot 已经完成 Nacos 注册。initialDelaySeconds 设到 40 秒左右给 JVM 启动和注册留时间太短会导致新 Pod 一直处于未就绪状态。这里没有把 Nacos 地址写死在镜像里而是通过环境变量 NACOS_ADDR 注入。好处是同一套镜像可以部署到 dev 和 prod 两个命名空间Nacos 地址不同也不需要重新构建镜像。后端 application.yml 里对应写成 spring.cloud.nacos.server-addr${NACOS_ADDR:nacos-headless:8848}默认值用于本地没有环境变量时的调试。前端的 Deployment 不带 readinessProbe 也可以Nginx 启动非常快TCP 探针足够。但如果追求稳定可以配一个 httpGet 打 /health 或者直接用 / 能返回 200 就认为就绪。Ingress 单独配把域名解析到前端 Service 的 80 端口即可。5. 部署翻车记录从服务注册不上到404的五个常见坑5.1 现象Pod起来但Nacos控制台查不到实例排查了一圈是地址配错这个坑我见过太多次。后端 Pod 状态 Running日志也没有明显报错但 Nacos 控制台服务列表里空荡荡的。最常见的原因是 bootstrap.yml 里 server-addr 写了外网 IP 或者 localhost。在 K8s 里Pod 的网络命名空间是独立的Pod 里的 localhost 就是 Pod 自己不是宿主机更不是 Nacos。解决把 server-addr 改成集群内的 Service 名称 nacos-headless:8848或者写成 nacos-0.nacos-headless.demo.svc.cluster.local:8848。改完配置后重新构建镜像或通过环境变量注入再查看日志里是否出现 Nacos 注册成功的关键字。个别情况下还要确认命名空间参数如果代码里指定了一个不存在的 namespaceNacos 会静默创建或不注册控制台里自然看不到。5.2 现象前端请求/api返回502原因是proxy_pass少了斜杠前端页面能打开Nginx 日志里看到大量 502。用 kubectl exec 进 Nginx 容器curl http://demo-backend:8080/actuator/health 如果通问题大概率出在 proxy_pass 的路径规则。有的写法是 proxy_pass http://demo-backend:8080/; 后端接口定义带 /api 前缀被 Nginx 吃掉一层路径SpringBoot 返回 404 或 502。解决先用 curl 验证后端 Service 的真实接口路径再决定 proxy_pass 末尾是否加斜杠。经验是后端 controller 已经是完整路径时proxy_pass 不带斜杠最省心。这类问题在本地 docker-compose 里可能不存在因为本地网络和路径映射跟 K8s 不完全一致建议部署后第一时间 curl 探测。5.3 现象Nacos配置改了但接口拿到的还是旧值动态刷新没生效配置中心里的配置在控制台改了接口返回的值纹丝不动。查日志能看到 RefreshEvent 相关输出说明客户端收到了推送但业务 Bean 没有重新构建。原因通常是两种Bean 没有加 RefreshScope或者配置是通过 Value 注入到了普通 Service 里而这个 Service 被其他 Bean 持有代理没有生效。解决在需要动态刷新的类上加 RefreshScope同时确保这个类不要被 final 修饰。配置项集中放到一个 Properties 类里更利于管理。另外检查 dataId 是否匹配SpringBoot 项目如果 spring.application.namedemo-backendNacos 上的 dataId 必须是 demo-backend.yaml后缀要跟 bootstrap.yml 里的 file-extension 一致。改错了命名空间也会导致拉不到。5.4 现象Nacos启动后反复重启日志里全是MySQL连接失败Nacos 容器日志显示 Unable to connect to MySQL或者 Communications link failure。原因不只是地址写错还有可能是 MySQL 连接串里的密码带了特殊字符。比如密码是 Nacos123 符号在环境变量里没问题但如果拼进 JDBC 连接串会被解析成参数分隔符导致连接失败。另一个原因是 MySQL 8.0 的认证插件默认 caching_sha2_passwordNacos 2.0.3 的数据库驱动版本可能不兼容。解决MYSQL_SERVICE_PASSWORD 里尽量避免 和 # 这种字符改用字母数字组合如 Nacos123456。如果必须用特殊字符在连接串里做 URL 编码 写成 %40。MySQL 8.0 建用户时指定 mysql_native_password或者用 CREATE USER nacos% IDENTIFIED WITH mysql_native_password BY Nacos123456; 来兼容旧驱动。5.5 现象vue页面刷新直接404try_files兜底写法不对前端路由刷新后 404或者跳到 Nginx 默认页。原因基本是 location / 里没有 try_files或者写了 try_files $uri $uri/ 404。在 hash 路由模式下这个坑不会出现只有 history 模式才需要服务端配合。还有一种情况是 Nginx 配置里写了 alias 而不是 root文件路径解析错乱静态资源全部加载失败。解决用 root 指向 /usr/share/nginx/htmllocation / 里写 try_files $uri $uri/ /index.html;。注意 /index.html 前有斜杠表示从 root 目录开始找。改完配置后先 docker build 本地验证也可以直接把 ConfigMap 里的配置改掉后滚动重启前端 DeploymentNginx 会重新加载配置。另外登录页路由如果是 /login 这类与真实文件重名的路径也要靠 try_files 兜底属于正常现象。6. 部署后验证与进阶套路从端口转发到一次配置热更新6.1 用kubectl port-forward把Nacos控制台拉到本地验证集群内的 Nacos 控制台不需要对外开放本地调试时用 port-forward 最方便。命令如下kubectl port-forward -n demo pod/nacos-0 8848:8848本地打开 http://localhost:8848/nacos 就能看到登录页。这样既验证了 Nacos 的 Service 端口映射也避免把控制台暴露到公网减少未授权访问风险。验证完直接 CtrlC 关掉不需要删除任何 Service。后端接口验证同理把某个后端 Pod 的 8080 端口转发到本地用 curl 打健康检查接口kubectl port-forward -n demo pod/demo-backend-xxxx 8080:8080 curl http://localhost:8080/actuator/health这一步能确认 SpringBoot 容器内部的服务是否正常排除 Nginx 和 Ingress 层的问题。6.2 确认服务注册、配置热更新一次跑通的完整步骤按照下面的顺序检查基本能确认整套链路是通的。第一步在 Nacos 控制台的服务列表里看 demo-backend 是否在线实例 IP 应该对应 Pod 的 IP。第二步在配置列表里新建或修改 demo-backend.yaml随便改一个开关项然后在后端接口里观察是否自动变更。第三步从前端页面发起 /api 请求抓包或看 Nginx 日志确认请求转发到了 demo-backend Service。这套验证做完前端静态资源、Nginx 反向代理、服务发现、配置中心四个环节全部覆盖。如果哪一步不通按照层级排查先看 Pod 日志再看 Service DNS 解析最后看网络策略。不要一上来就怀疑代码K8s 环境里 80% 的问题出在配置和网络。6.3 三个进阶习惯固定镜像tag、探针就绪、滚动更新参数镜像 tag 不要用 latest用日期或 commit 号比如 20240501-abc123。latest 在 K8s 里会带来缓存问题Pod 调度到新节点时可能拉不到最新镜像排障时也不知道线上跑的是哪次构建。发布时改 tag 就能精确知道集群里部署的代码版本。生产环境一定要加 readinessProbe并且健康检查路径指向 actuator/health。滚动更新时配置 maxSurge 和 maxUnavailable比如 maxSurge25%、maxUnavailable25%能保证更新过程中始终有一定数量的旧 Pod 在服务。如果后端启动要 40 秒更新策略要留够时间否则会出现长时间无可用副本。我现在做这类部署的习惯是先跑通最小链路再补细节先单副本把 Nacos、后端、前端串起来确认注册和路由没问题再调副本数、加探针、配滚动更新。这套组合在阿里云 ACK 上跑了一年多最大的收获是把版本兼容表和端口规则贴在团队文档里每次换版本先查表再动手。希望帮到你。本文还有配套的精品资源点击获取