Spring Boot 4.0 Docker 与 Kubernetes 生产部署
前言
能执行 java -jar 不等于能部署生产。镜像需要可复现,容器不能以 root 运行,Kubernetes 需要知道实例何时可以接流量、何时必须重启,还要在滚动更新失败时保留回退路径。
本章为订单项目创建多阶段 Docker 镜像和完整 Kubernetes 清单。
读者需要完成 Actuator 监控章节,并了解 Docker 与 kubectl。源码位于 dvsusan/spring-boot4-demo。
最终结果
项目新增:
Dockerfile
.dockerignore
deploy/k8s/
├── namespace.yaml
├── configmap.yaml
├── secret.example.yaml
├── deployment.yaml
├── service.yaml
├── hpa.yaml
└── kustomization.yaml镜像以非 root 用户启动,Deployment 使用 readiness/liveness 探针并执行 maxUnavailable=0 的滚动更新。

图 1:新 Pod 只有在 readiness 通过后才接流量,旧 Pod 随后才退出。
第 1 步:编写多阶段 Dockerfile
# 构建阶段固定 Maven 与 JDK 主版本。
FROM maven:3.9.9-eclipse-temurin-21 AS build
WORKDIR /workspace
COPY pom.xml .
COPY demo-common/pom.xml demo-common/pom.xml
COPY demo-greeting-starter/pom.xml demo-greeting-starter/pom.xml
COPY demo-order/pom.xml demo-order/pom.xml
COPY demo-persistence/pom.xml demo-persistence/pom.xml
COPY demo-integration/pom.xml demo-integration/pom.xml
COPY demo-web/pom.xml demo-web/pom.xml
RUN mvn -B -q -DskipTests dependency:go-offline
COPY . .
RUN mvn -B -DskipTests package
# 运行镜像只保留 JRE 和可执行 JAR。
FROM eclipse-temurin:21-jre
WORKDIR /app
RUN groupadd --system spring && useradd --system --gid spring spring
COPY --from=build /workspace/demo-web/target/demo-web-1.0.0-SNAPSHOT.jar app.jar
RUN chown -R spring:spring /app
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "/app/app.jar"]多阶段构建不会把 Maven、源码和构建缓存带进运行镜像。先复制 POM 再复制源码,可以提高依赖层缓存命中率。
第 2 步:构建并运行镜像
docker build -t spring-boot4-demo:local .
docker run --rm \
-p 18108:8080 \
-e SPRING_PROFILES_ACTIVE=prod,chapter8 \
spring-boot4-demo:local验证:
curl http://localhost:18108/actuator/health当前执行环境没有可用的 Docker daemon,因此本次只完成了 Dockerfile 与部署清单的静态校验,没有声称镜像已经实际构建成功。
第 3 步:准备 Kubernetes 配置
ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: spring-boot4-demo-config
namespace: spring-boot4-demo
data:
SPRING_PROFILES_ACTIVE: "prod,db,chapter8"
SERVER_PORT: "8080"
JAVA_TOOL_OPTIONS: "-XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError"
MANAGEMENT_HEALTH_SHOW_DETAILS: "never"
DB_URL: "jdbc:postgresql://postgresql:5432/spring_boot4"
OTEL_TRACING_EXPORT_ENABLED: "false"
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://otel-collector:4318/v1/traces"db Profile 会启用 PostgreSQL 和 Flyway,chapter8 负责健康探针与监控端点。DB_URL 中的 postgresql 是 Kubernetes Service 名称;接入云数据库时改成实际可达地址。MANAGEMENT_HEALTH_SHOW_DETAILS=never 避免生产健康端点暴露数据库等组件信息。
密码和 Token 放在 Secret,不放进 ConfigMap。应用从 application-db.yml 读取 DB_USERNAME 与 DB_PASSWORD,所以 Secret 的键名不能自行改名。secret.example.yaml 只展示字段结构,不能用示例值上线。
部署前要确保目标命名空间里已有 PostgreSQL Service;本示例不把有状态数据库和业务应用塞进同一份清单。首次连接时 Flyway 会执行 classpath:db/migration 下的迁移脚本。
kubectl create namespace spring-boot4-demo
kubectl -n spring-boot4-demo create secret generic spring-boot4-demo-secret \
--from-literal=DB_USERNAME='<username>' \
--from-literal=DB_PASSWORD='<password>'第 4 步:配置 Deployment 探针和资源
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1容器关键配置:
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: http
initialDelaySeconds: 20
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
initialDelaySeconds: 45
periodSeconds: 15
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1GiReadiness 失败只停止接流量,liveness 失败会重启容器。数据库暂时不可用时通常不应立即触发 liveness,否则所有实例会一起重启。
第 5 步:配置 Service 和 HPA
Service 把 80 端口转发到容器 http:
spec:
selector:
app.kubernetes.io/name: spring-boot4-demo
ports:
- name: http
port: 80
targetPort: httpHPA 按 CPU 在 2–6 个副本之间调整:
minReplicas: 2
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65HPA 依赖集群 Metrics Server。只配置 HPA 而没有资源 requests,CPU 利用率无法正确计算。
第 6 步:渲染并部署清单
kubectl kustomize deploy/k8s
docker build \
-t ghcr.io/dvsusan/spring-boot4-demo:1.0.0 .
docker push ghcr.io/dvsusan/spring-boot4-demo:1.0.0
kubectl apply -k deploy/k8s
kubectl -n spring-boot4-demo rollout status \
deployment/spring-boot4-demo \
--timeout=180s部署前先创建真实 Secret。secret.example.yaml 不在 Kustomization 资源中,避免误创建占位凭据。
生产检查清单
- 使用不可变镜像 Tag,不在生产使用
latest。 - JVM 内存上限小于容器 memory limit。
- readiness 与 liveness 分开配置。
- 设置
terminationGracePeriodSeconds和应用优雅停机。 - 至少两个副本,并配置 Pod 反亲和或拓扑分布。
- Secret 由密钥管理系统注入,不提交 Git。
- 保留 Deployment revision,并有回滚脚本。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| Pod 一直 CrashLoopBackOff | 配置缺失或应用启动失败 | 查看 kubectl logs --previous |
| Pod Running 但不接流量 | readiness 未通过 | 检查 readiness 端点和服务依赖 |
| 容器被 OOMKilled | JVM 堆与容器限制不匹配 | 使用 MaxRAMPercentage 并留出元空间 |
| HPA 不扩容 | Metrics Server 缺失或未设 requests | 安装 Metrics Server,补资源请求 |
| 发布卡住 | 新 Pod 未 ready | rollout status 后执行 rollout undo |
练习题
增加 PodDisruptionBudget 和 topologySpreadConstraints,保证节点维护时至少保留一个可用实例。验收标准是模拟一个节点不可用时,服务仍能通过 readiness 接收请求。
总结
生产部署关注镜像可复现、进程最小权限、探针语义、资源预算和渐进发布。能启动只是起点,能在异常时安全停止和回退才是部署能力。
下一篇把这些步骤自动化成可重复的 CI/CD 发布流水线。
上一节:Actuator 与 OpenTelemetry
下一节:CI/CD 发布与回滚
相关阅读:Spring Boot 4 配置管理
返回课程目录
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
