
摘要:做 SpringCloud 微服务开发的同学,大概率都踩过这些坑:本地跑的顺风顺水,一上线就因为环境不一致崩掉;十几个微服务手动部署要半小时,还容易漏改配置;流量突增时手动扩缩容根本赶不上,服务直接被打挂;某个实例宕机还要人工登录服务器重启,故障恢复慢到离谱。
本文基于我 3 个线上生产项目的落地经验,从 0 到 1 带你完成 SpringCloud 微服务从 Docker 镜像构建到 K8s 集群全量上线的完整流程。所有配置都是生产环境验证过的,可直接复制使用,同时把我踩过的所有坑都整理成了避坑指南,帮你少走半年弯路,适合后端开发、运维、架构师直接落地参考。
1 前言:为什么 SpringCloud 项目必须用 Docker+K8s 部署?
先给大家算一笔账:传统的手动部署模式下,一个 10 个微服务的项目,一次全量上线要做这些事:打包→上传服务器→停服务→备份→改配置→启服务→验证,一套下来至少 30 分钟,还很容易出现配置漏改、端口冲突、环境依赖缺失的问题。
而 Docker+K8s 的部署模式,能彻底解决这些痛点:
这篇文章不讲虚的理论,只讲能直接复制到生产环境的实战内容,跟着做就能完成上线。
2 整体架构设计与版本统一(避坑第一步)
2.1 整体部署架构图

2.2 生产验证过的版本清单(避免 90% 的兼容性坑)
很多人部署失败,第一步就栽在了版本不兼容上。这里给大家一套我在 3 个生产项目里跑了 1 年多的稳定版本组合,不要盲目用最新版,坑多到你踩不完:
| JDK | OpenJDK 8u382 | 生产环境最稳定的 LTS 版本,兼容性拉满 |
| SpringBoot | 2.7.15 | 2.x 最终稳定版,无高危漏洞 |
| SpringCloud | 2021.0.8 | 与 SpringBoot 完美适配,无 API 废弃问题 |
| SpringCloud Alibaba | 2021.0.5.0 | 对应 SpringCloud 版本,适配 Nacos 2.x |
| Docker | 24.0.6 | 稳定版,无兼容性问题 |
| Kubernetes | 1.26.10 | 长期支持版,国内云厂商普遍兼容 |
| 私有镜像仓库 | Harbor 2.8.4 | 企业级镜像管理,支持权限控制、漏洞扫描 |
| 网关 | SpringCloud Gateway 3.1.8 | 适配 SpringCloud 版本,性能稳定 |
| 注册中心 | Nacos 2.2.3 | 国内微服务首选,适配 K8s 部署 |
3 SpringCloud 项目 Docker 容器化全流程
3.1 前置准备:项目规范调整
在写 Dockerfile 之前,先把项目做几个小调整,避免后续踩坑:
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s
3.2 多阶段构建 Dockerfile 编写(生产级优化版)
很多教程的 Dockerfile 都是单阶段构建,不仅镜像体积大(动辄 800M+),还会把源码、maven 环境都打包进去,有安全隐患。这里给大家一套生产级的多阶段构建 Dockerfile,优化拉取速度、减小体积、提升安全性。
# 第一阶段:构建阶段,用maven镜像完成编译打包
FROM maven:3.8.6-openjdk-8 AS builder
# 设置工作目录
WORKDIR /app
# 先复制pom.xml,下载依赖,利用Docker缓存层,只要pom不变就不会重新下载依赖
COPY pom.xml .
RUN mvn dependency:go-offline -B
# 复制源码
COPY src ./src
# 打包,跳过单元测试,生产环境可根据需求开启
RUN mvn clean package -DskipTests
# 第二阶段:运行阶段,用精简JRE镜像,只保留运行所需的内容
FROM openjdk:8-jre-slim
# 维护人信息
MAINTAINER 你的昵称 <你的邮箱>
# 解决容器时区差8小时的问题,90%的人都踩过这个日志时间不对的坑
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 设置工作目录
WORKDIR /app
# 从构建阶段复制最终的jar包,只复制这一个文件,大幅减小镜像体积
COPY –from=builder /app/target/*.jar app.jar
# 用非root用户运行容器,提升生产环境安全性,避免容器逃逸风险
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /app
USER appuser
# 暴露服务端口
EXPOSE 8081
# 启动命令,支持JVM参数和Spring参数通过环境变量注入,不用重新打包镜像
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar $SPRING_OPTS"]

这套 Dockerfile 的核心优化点:
3.3 镜像构建与本地验证
# 构建镜像,注意末尾的点不能少
docker build -t user-service:1.0.0 .
# 本地运行验证,替换成你自己的注册中心地址等配置
docker run -d -p 8081:8081 \\
-e JAVA_OPTS="-Xms512m -Xmx512m" \\
-e SPRING_OPTS="–spring.profiles.active=test –nacos.server-addr=192.168.1.100:8848" \\
–name user-service-test \\
user-service:1.0.0
# 查看容器运行状态
docker ps
# 查看容器日志,确认服务启动成功
docker logs -f user-service-test
# 验证健康检查接口,返回UP就说明服务正常
curl http://127.0.0.1:8081/actuator/health
3.4 镜像推送到私有仓库
生产环境不要用 Docker Hub,一定要搭建自己的私有镜像仓库(推荐 Harbor),镜像推送到仓库后,K8s 集群才能拉取到。
# 给镜像打标签,格式:仓库地址/命名空间/镜像名:版本号
docker tag user-service:1.0.0 harbor.你的域名.com/prod-cloud/user-service:1.0.0
# 登录私有镜像仓库
docker login harbor.你的域名.com -u 你的用户名 -p 你的密码
# 推送镜像到私有仓库
docker push harbor.你的域名.com/prod-cloud/user-service:1.0.0
4 K8s 集群环境与前置准备
这里不展开讲 K8s 集群的搭建,新手直接用阿里云 ACK、腾讯云 TKE 等云厂商托管集群,一键创建,不用自己折腾高可用;有运维能力的可以用 kubeadm 自建集群。重点讲和 SpringCloud 部署相关的前置准备:
5 SpringCloud 微服务 K8s 编排核心 yaml 配置(全量可复制)
这部分是整个部署的核心,所有 yaml 都是我生产环境验证过的,带详细注释,直接替换成你自己的镜像地址、配置即可使用。

5.1 Namespace:环境隔离配置
首先创建命名空间,把生产和测试环境的资源完全隔离开,避免配置混乱。
# 01-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: prod-cloud
labels:
name: prod-cloud
env: production
—
apiVersion: v1
kind: Namespace
metadata:
name: test-cloud
labels:
name: test-cloud
env: test
执行命令创建:kubectl apply -f 01-namespace.yaml
5.2 ConfigMap:外部化配置管理
用来存放所有微服务的公共非敏感配置,比如环境标识、注册中心地址、端口等,不用写死在镜像里,改配置不用重新打包。
# 02-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cloud-common-config
namespace: prod-cloud
data:
# 公共环境配置
SPRING_PROFILES_ACTIVE: "prod"
NACOS_SERVER_ADDR: "nacos-headless.prod-middleware:8848"
NACOS_NAMESPACE: "prod-cloud-xxx"
# 各服务端口配置
GATEWAY_PORT: "8080"
USER_SERVICE_PORT: "8081"
ORDER_SERVICE_PORT: "8082"
GOODS_SERVICE_PORT: "8083"
执行命令创建:kubectl apply -f 02-configmap.yaml
5.3 Secret:敏感信息管理
用来存放数据库密码、Nacos 账号密码、镜像仓库密钥等敏感信息,不要用 ConfigMap 存放敏感内容,Secret 是 base64 编码的,安全性更高。
首先是镜像仓库拉取密钥,让 K8s 能拉取 Harbor 私有仓库的镜像:
# 03-registry-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: harbor-registry-secret
namespace: prod-cloud
type: kubernetes.io/dockerconfigjson
data:
# 这里填你本地docker login后生成的~/.docker/config.json的base64编码
# 生成命令:cat ~/.docker/config.json | base64 -w 0
.dockerconfigjson: 你的base64编码内容
然后是业务敏感信息 Secret:
# 04-cloud-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cloud-secret
namespace: prod-cloud
type: Opaque
data:
# 所有值都要用base64编码,生成命令:echo -n "你的密码" | base64
DB_PASSWORD: 你的数据库密码base64编码
NACOS_USERNAME: 你的Nacos用户名base64编码
NACOS_PASSWORD: 你的Nacos密码base64编码
REDIS_PASSWORD: 你的Redis密码base64编码
执行命令创建:kubectl apply -f 03-registry-secret.yaml -f 04-cloud-secret.yaml
5.4 Deployment:微服务部署编排(核心)
这是最核心的配置,定义了微服务的镜像、副本数、资源限制、健康检查、环境变量、优雅停机等所有核心配置,以用户服务为例,其他服务只需要替换镜像名、端口、名称即可。
# 05-user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: prod-cloud
labels:
app: user-service
version: 1.0.0
spec:
# 生产环境副本数至少2个,保证高可用
replicas: 2
# 滚动更新策略:先启动新Pod,就绪后再销毁旧Pod,实现零停机更新
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
# 标签选择器,和Pod的标签严格对应
selector:
matchLabels:
app: user-service
# Pod模板定义
template:
metadata:
labels:
app: user-service
spec:
# 引用镜像仓库密钥,拉取私有镜像
imagePullSecrets:
– name: harbor-registry-secret
containers:
– name: user-service
# 替换成你自己的镜像地址
image: harbor.你的域名.com/prod-cloud/user-service:1.0.0
imagePullPolicy: IfNotPresent
# 容器端口,和服务配置的端口一致
ports:
– containerPort: 8081
name: http
protocol: TCP
# 环境变量注入,从ConfigMap和Secret中读取,不用写死在镜像里
env:
# JVM参数,生产环境根据服务器配置调整
– name: JAVA_OPTS
value: "-Xms1g -Xmx1g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/dump/heapdump.hprof"
# 从ConfigMap读取公共配置
– name: SPRING_PROFILES_ACTIVE
valueFrom:
configMapKeyRef:
name: cloud-common-config
key: SPRING_PROFILES_ACTIVE
– name: NACOS_SERVER_ADDR
valueFrom:
configMapKeyRef:
name: cloud-common-config
key: NACOS_SERVER_ADDR
– name: NACOS_NAMESPACE
valueFrom:
configMapKeyRef:
name: cloud-common-config
key: NACOS_NAMESPACE
# 从Secret读取敏感信息
– name: NACOS_USERNAME
valueFrom:
secretKeyRef:
name: cloud-secret
key: NACOS_USERNAME
– name: NACOS_PASSWORD
valueFrom:
secretKeyRef:
name: cloud-secret
key: NACOS_PASSWORD
# 资源限制:生产环境必须配置,避免单个服务占用所有节点资源
resources:
# 最小资源需求,调度时会找满足这个配置的节点
requests:
cpu: "500m"
memory: "1Gi"
# 最大资源限制,超过会被限制或重启
limits:
cpu: "1000m"
memory: "1Gi"
# 启动探针:解决SpringCloud服务启动慢,被K8s误杀的问题(90%的人踩过这个坑)
startupProbe:
httpGet:
path: /actuator/health
port: http
# 最大等待30*10=300秒,足够SpringCloud服务启动完成
failureThreshold: 30
periodSeconds: 10
# 就绪探针:服务准备好接收流量才会加入Service负载均衡
readinessProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 5
periodSeconds: 5
# 存活探针:服务运行异常时自动重启,实现故障自愈
livenessProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 30
periodSeconds: 10
# 优雅停机钩子:停止前先等待10秒,让流量完全切走再关闭服务
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
# 日志、堆转储文件挂载,避免容器销毁后日志丢失
volumeMounts:
– name: app-logs
mountPath: /app/logs
– name: heap-dump
mountPath: /app/dump
# 数据卷挂载,生产环境建议用PVC,测试环境可以用hostPath
volumes:
– name: app-logs
hostPath:
path: /data/logs/user-service
type: DirectoryOrCreate
– name: heap-dump
hostPath:
path: /data/dump/user-service
type: DirectoryOrCreate
5.5 Service:服务发现与内部通信
Service 为 Pod 提供固定的访问地址,实现服务发现,集群内的其他服务可以通过 Service 名称访问,不用关心 Pod 的 IP 变化。
# 06-user-service-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: prod-cloud
labels:
app: user-service
spec:
# ClusterIP:仅集群内部可访问,微服务之间调用用这个类型
type: ClusterIP
ports:
– port: 8081
targetPort: http
name: http
protocol: TCP
# 绑定对应的Deployment的Pod标签
selector:
app: user-service
部署后,集群内的其他服务可以通过http://user-service:8081访问用户服务,K8s 的 CoreDNS 会自动解析。
5.6 Ingress:外网流量入口
网关是整个微服务集群的入口,外网流量需要通过 Ingress 暴露,不要用 NodePort,端口有限且不安全,生产环境用 Ingress + 域名的方式。
# 07-gateway-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cloud-gateway-ingress
namespace: prod-cloud
annotations:
# 指定用Nginx Ingress Controller
kubernetes.io/ingress.class: "nginx"
# 超时配置,适配微服务接口超时
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
# 生产环境配置HTTPS重定向
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
# HTTPS证书配置,生产环境必须配置
tls:
– hosts:
– api.你的域名.com
secretName: api-tls-secret
# 路由规则
rules:
– host: api.你的域名.com
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8080
部署后,把你的域名解析到 Ingress Controller 的外网 IP,外网用户就可以通过域名访问你的微服务集群了。
5.7 HPA:自动扩缩容配置
根据 CPU 使用率自动调整 Pod 副本数,应对流量突增,闲时自动缩容节省资源。
# 08-user-service-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: user-service-hpa
namespace: prod-cloud
spec:
# 绑定对应的Deployment
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
# 最小和最大副本数
minReplicas: 2
maxReplicas: 10
# 扩缩容指标:CPU使用率超过70%自动扩容
metrics:
– type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
6 完整部署上线流程(一步一步跟着做)
所有 yaml 文件准备好后,按照这个顺序执行,就能完成全量上线:
# 创建命名空间
kubectl apply -f 01-namespace.yaml
# 创建ConfigMap和Secret
kubectl apply -f 02-configmap.yaml
kubectl apply -f 03-registry-secret.yaml -f 04-cloud-secret.yaml
# 部署网关、用户、订单、商品等服务的Deployment和Service
kubectl apply -f 05-user-service-deployment.yaml -f 06-user-service-svc.yaml
kubectl apply -f 07-order-service-deployment.yaml -f 08-order-service-svc.yaml
kubectl apply -f 09-gateway-service-deployment.yaml -f 10-gateway-service-svc.yaml
kubectl apply -f 11-gateway-ingress.yaml
kubectl apply -f 12-user-service-hpa.yaml -f 13-order-service-hpa.yaml
# 查看所有Pod状态,STATUS为Running就是正常
kubectl get pods -n prod-cloud
# 查看Deployment状态,READY为2/2就是正常
kubectl get deployments -n prod-cloud
# 查看Service状态
kubectl get svc -n prod-cloud
# 查看Ingress状态
kubectl get ingress -n prod-cloud
# 查看HPA状态
kubectl get hpa -n prod-cloud
7 生产环境核心优化与踩坑实录(热榜核心干货)
这部分是我 3 个生产项目踩了无数坑总结出来的经验,90% 的教程都不会讲,也是你上线后能不能稳定运行的关键。
7.1 Docker 镜像优化:从 800M 到 120M 的技巧
- 必须用多阶段构建,不要把 maven、源码放在最终镜像里
- 用精简的基础镜像,比如openjdk:8-jre-slim,比默认的openjdk:8小 60%,甚至可以用 alpine 镜像,体积更小
- 不要把日志、配置文件打包到镜像里,用外部挂载和环境变量注入
- 清理镜像里的无用缓存、文档、临时文件,减小镜像体积
- 优化后的镜像,拉取速度提升 5 倍以上,上线时间大幅缩短
7.2 SpringCloud 服务在 K8s 里的服务发现大坑
很多人部署后会出现服务之间调用不通的问题,90% 都是这两个原因:
7.3 资源限制与 OOM Kill 避坑
- 生产环境必须配置requests和limits,而且内存的 requests 和 limits 必须设置成一样的,这样 Pod 的 QoS 等级是 Guaranteed,K8s 节点内存不足时,不会优先杀掉这种 Pod
- JVM 的最大堆内存Xmx,一定要比 limits 的内存小 20% 以上,比如 limits 是 1G,Xmx 最多设置 800M。因为 JVM 除了堆内存,还有非堆内存、元空间、栈内存、直接内存等,不然会被容器的 OOM Killer 直接杀掉,这个坑我踩了无数次!
7.4 健康检查与优雅停机的正确姿势
- 必须配置启动探针,SpringCloud 服务启动慢,没有启动探针的话,就绪探针和存活探针会把启动中的 Pod 误杀
- 优雅停机必须配置preStop钩子,K8s 停止 Pod 时,会先把 Pod 从 Service 的负载均衡里摘掉,再发送 SIGTERM 信号,sleep 10可以让流量完全切走,再停止服务,避免请求中断
- 健康检查的接口不要加权限校验,不然 K8s 访问会被拒绝,导致 Pod 一直重启
7.5 配置中心与 K8s ConfigMap 的最佳实践
很多人会纠结用 Nacos 配置中心还是 K8s ConfigMap,我的生产最佳实践是:
- 公共的、非敏感的、不常变的配置,比如 Nacos 地址、环境标识,放在 ConfigMap 里
- 业务相关的、需要动态刷新的配置,比如接口超时、限流规则、功能开关,放在 Nacos 配置中心里,不用重启服务就能生效
- 所有敏感信息,比如密码、密钥,必须放在 Secret 里,绝对不能写在配置文件或 ConfigMap 里
8 日常运维常用命令
整理了一套上线后日常运维最常用的 kubectl 命令,收藏起来备用:
# 查看指定命名空间的所有Pod
kubectl get pods -n prod-cloud
# 查看Pod的详细信息,排查启动失败、调度失败的问题
kubectl describe pod <pod名称> -n prod-cloud
# 实时查看Pod日志
kubectl logs -f <pod名称> -n prod-cloud
# 查看Pod的前100行日志
kubectl logs –tail=100 <pod名称> -n prod-cloud
# 进入Pod内部调试
kubectl exec -it <pod名称> -n prod-cloud — /bin/bash
# 查看Deployment的滚动更新状态
kubectl rollout status deployment/user-service -n prod-cloud
# 回滚Deployment到上一个版本
kubectl rollout undo deployment/user-service -n prod-cloud
# 查看Deployment的发布历史
kubectl rollout history deployment/user-service -n prod-cloud
# 手动扩容/缩容Deployment副本数
kubectl scale deployment/user-service –replicas=3 -n prod-cloud
9 总结
这套 Docker+K8s 的部署方案,是我在多个生产项目里验证过的,能彻底解决 SpringCloud 微服务部署的痛点:
微服务架构的核心,不仅是业务的拆分,更是运维体系的升级。Docker+K8s 是微服务部署的事实标准,也是后端开发、架构师必须掌握的技能。
如果你在部署过程中遇到任何问题,欢迎在评论区留言,我会一一回复。如果这篇文章对你有帮助,欢迎点赞、收藏、关注,后续会更新更多 SpringCloud 生产级落地的干货内容。




