首页 / Spring Boot 入门教程 / 云原生与高效部署

Spring Boot 入门教程

云原生与高效部署

本教程共 48 篇 · 第 45 篇 · 更新于 2026-08-13 · 约 5 分钟阅读

Spring Boot云原生Buildpacks优雅停机资源优化部署策略Kubernetes

本节目标:掌握 Buildpacks 免 Dockerfile 构建镜像、优雅停机配置、容器内存优化,了解常见的生产部署策略。

云原生要解决什么

应用进了容器,只是第一步。生产环境还要回答一堆问题:

  • 镜像怎么构建?谁来维护 Dockerfile?
  • 发布时怎么不丢请求?
  • 内存怎么配,容器不 OOM?
  • 升级怎么平滑,故障怎么恢复?

这章把这些「最后一公里」问题逐个拆开。

Buildpacks:不用写 Dockerfile

上一节手写 Dockerfile 是通用方案。Spring Boot 还有官方推荐的捷径:Cloud Native Buildpacks

Buildpacks 的思路:你不用描述「怎么构建」,只要告诉它「我要什么」。构建器(Builder)自动探测项目类型、选基础镜像、装运行时、配置启动命令,全程零 Dockerfile。

一条命令出镜像:

mvn spring-boot:build-image

执行时自动做几件事:

  • 用 Paketo 构建器识别 Spring Boot 应用。
  • 自动选 JDK 版本、配置内存参数。
  • 生成带层缓存的镜像,直接进本地 Docker 守护进程。
  • 镜像名默认 项目名:版本号,可用 -Dspring-boot.build-image.imageName=registry/demo:1.0 指定。
# 指定镜像名
mvn spring-boot:build-image -Dspring-boot.build-image.imageName=myregistry/demo:1.0

Buildpacks 的镜像开箱即用:非 root 用户、合理的内存设置、健康检查支持都配好了。不想维护 Dockerfile 的团队,这是最省事的路。

Note

Buildpacks 支持 layers.idx 分层索引,上一节的分层优化在 Buildpacks 里同样生效。生成的镜像层和分层 Jar 的层一一对应,缓存复用效果一致。

优雅停机:不丢一个请求

发布时最怕什么?旧进程被直接杀死,正在处理的请求中断,用户看到 502。

优雅停机(Graceful Shutdown):收到停止信号后,先停止接收新请求,等正在处理的请求完成,再关进程。

Spring Boot 4.x 中,三个内嵌服务器(Tomcat、Jetty、Reactor Netty)默认启用优雅停机。收到 SIGTERM 信号后:

  1. 网络层停止接收新连接。
  2. 正在处理的请求继续执行。
  3. 全部结束后,关闭应用上下文。

超时时间可以配置:

spring:
  lifecycle:
    timeout-per-shutdown-phase: "20s"

20 秒内没处理完的请求会被强制结束。时间给太长,发布流程会拖;给太短,慢请求会被掐断,按业务情况调。

Note

版本差异:Spring Boot 3.x 要显式配置 server.shutdown: graceful 才启用。4.x 默认就是优雅停机,server.shutdown 的默认值从 immediate 变成了 graceful。看到旧教程教配置这个属性,是 3.x 的写法。

配合 Kubernetes 的流程:K8s 先发 SIGTERM,应用优雅收尾;terminationGracePeriodSeconds 给足超时时间,两边要匹配。

健康检查:K8s 的生命线

Kubernetes 靠探针判断应用死活:

  • 就绪探针:应用能接流量了吗?不通过就摘流量。
  • 存活探针:应用还活着吗?不通过就重启。

Spring Boot Actuator 的 /actuator/health 就是现成的探针端点。加上依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

K8s 里这样配:

livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080

Spring Boot 4.x 提供了独立的 livenessreadiness 端点,语义和 K8s 探针对齐。就绪探针没通过时,流量不会进来,配合优雅停机,发布基本无损。

容器里的 JVM:内存怎么给

容器有内存上限,JVM 却默认按宿主机内存算。最经典的故障:容器限了 512M,JVM 堆按宿主机 32G 的 1/4 算,一压测就 OOM。

JVM 10+ 默认支持容器感知(UseContainerSupport),但堆大小仍按容器内存的一定比例算,具体比例不一定合适。生产建议显式控制:

java -XX:MaxRAMPercentage=75 -XX:InitialRAMPercentage=50 -jar app.jar
  • -XX:MaxRAMPercentage=75:堆最大占容器内存的 75%。JVM 自身、线程栈、Metaspace 还需要空间,别给满。
  • -XX:InitialRAMPercentage=50:启动时先分配一半,避免一次性占满。

两个参数配合 -Xmx 固定值选一个用。-Xmx512m 写死简单,但换容器规格就要改配置;百分比方案自动跟随容器内存,更云原生。

Warning

只设 -Xmx 不设 -XX:MaxRAMPercentage 也可以,但别忘了容器里还有 JVM 自身开销。堆给到 100% 内存,一样会 OOM。

高效部署:解压运行与 AOT 缓存

第 42 章讲过,胖 Jar 运行时从嵌套 Jar 加载类有少量开销。生产环境两种提速姿势:

解压运行(42 章已讲):

java -Djarmode=tools -jar demo.jar extract --destination application
java -jar application/demo.jar

AOT 缓存 / CDS(44 章已讲):训练一次生成缓存,启动时直接加载,启动时间能再砍一截。Java 25+ 用 AOT 缓存,旧版本用 CDS;21 LTS 可用,官方示例为 25。

两者叠加效果最好:解压形态 + AOT 缓存,是官方推荐的容器内 JVM 运行组合。第 43 章的 Dockerfile 里,RUN java -XX:AOTCacheOutput=app.aot -Dspring.context.exit=onRefresh -jar application.jar 就是在构建镜像时做训练。

部署策略:上线不背锅

镜像和配置都齐了,怎么发布?常见三种策略:

滚动更新(Rolling Update):逐个替换旧实例,新实例就绪后才继续替换下一个。K8s 默认行为,配好就绪探针就安全。发布期间新旧版本共存,注意数据库兼容:新代码要兼容旧数据结构。

蓝绿部署(Blue-Green):一套旧环境(蓝)、一套新环境(绿),全部部署完验证通过,一次性切流量。回滚就是切回蓝环境,秒级完成。成本是两套环境同时运行。

金丝雀发布(Canary):先放 5% 流量到新版本,观察指标正常再逐步放量。风险最小,但需要流量治理能力(Istio 这类服务网格常见)。

选型参考:小团队起步用滚动更新 + 就绪探针;对稳定性要求高、有预算跑双环境,用蓝绿;流量大、追求极致安全,上金丝雀。

生产检查清单

上线前对着过一遍:

  • 镜像:分层构建、非 root 用户、内存百分比参数。
  • 探针:/actuator/health/readiness/actuator/health/liveness 配置到位。
  • 停机:优雅停机默认开启,timeout-per-shutdown-phase 按业务调。
  • 日志:输出到标准输出(stdout),容器平台统一收集。
  • 配置:敏感信息走环境变量或密钥管理,不写进镜像。

小结

  • mvn spring-boot:build-image 用 Buildpacks 免 Dockerfile 出镜像。
  • 4.x 默认优雅停机,spring.lifecycle.timeout-per-shutdown-phase 调超时。
  • Actuator 的 liveness / readiness 端点对接 K8s 探针。
  • JVM 内存用 -XX:MaxRAMPercentage 跟随容器限制。
  • 发布策略:滚动更新起步,蓝绿、金丝雀按需升级。