
本文旨在解决Spring Boot应用在Kubernetes环境中启动后立即关闭的问题。核心原因在于Kubernetes的就绪性探针(Readiness Probe)在应用尚未完全初始化并准备好接受流量时,过早地判断应用为“未就绪”并触发终止。通过配置就绪性探针和存活性探针的`initialDelaySeconds`参数,为应用提供足够的启动时间,可以有效解决此问题,确保应用稳定运行。
在将Spring Boot应用部署到Kubernetes集群时,开发者可能会遇到应用在容器启动后立即终止的现象。尽管应用在本地开发环境或非Kubernetes的开发环境中运行良好,但在生产预发布(PP)等更严格的Kubernetes环境中,却出现启动后迅速关闭的问题。通过分析应用日志,我们通常会发现以下关键信息:
2022-11-30 13:11:12.110 INFO 1 --- [ main] c.a.f.MyApplication : Started MyApplication in 96.297 seconds (JVM running for 104.706) 2022-11-30 13:11:12.513 INFO 1 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' ... Application availability state ReadinessState changed to REFUSING_TRAFFIC
日志显示应用似乎成功启动("Started MyApplication..."),但紧接着出现了Application availability state ReadinessState changed to REFUSING_TRAFFIC,并且触发了关闭事件("Closing JPA EntityManagerFactory...","HikariPool-1 - Shutdown initiated...")。这表明应用在启动后不久就被外部机制判定为不可用并被终止。
理解Kubernetes的探针机制
Kubernetes为了确保部署的应用的健壮性和高可用性,引入了两种核心探针:存活性探针(Liveness Probe)和就绪性探针(Readiness Probe)。
-
存活性探针 (Liveness Probe)
- 作用: 用于检测容器内的应用是否正在运行。如果存活性探针失败,Kubernetes会认为该容器已死亡,并根据重启策略重启容器。
- 目的: 捕获应用死锁(例如,应用进程仍在运行但无法处理请求)的情况,通过重启来恢复服务。
-
就绪性探针 (Readiness Probe)
- 作用: 用于检测容器内的应用是否已准备好接收流量。如果就绪性探针失败,Kubernetes会从Service的Endpoint列表中移除该Pod的IP地址,停止向其发送流量。当探针成功时,Pod会被重新加入Endpoint列表。
- 目的: 确保流量只发送给完全初始化并能够响应请求的应用实例,避免在应用启动过程中或处理复杂初始化任务时将请求发送给未准备好的实例。
问题根源:就绪性探针的过早判断
从日志中ReadinessState changed to REFUSING_TRAFFIC这一行可以看出,问题在于Kubernetes的就绪性探针过早地对应用进行了健康检查。Spring Boot应用,尤其是包含数据库初始化(如Flyway)和JPA实体管理器加载等复杂逻辑的应用,启动过程可能需要较长时间。在此期间,尽管JVM已经启动,但应用可能尚未完全完成所有依赖注入、数据库连接池初始化或业务逻辑层的准备。
如果Kubernetes的就绪性探针在应用完全准备好之前就开始检查,并且应用尚未能响应探针请求(例如/actuator/health/readiness),或者其内部状态仍处于“REFUSING_TRAFFIC”,Kubernetes就会误判应用为“未就绪”。根据Kubernetes的默认行为,如果一个Pod长时间处于非就绪状态,或者其存活性探针失败,可能会导致Pod被终止并重新创建,从而陷入无限重启的循环。
解决方案:配置探针的初始延迟
为了解决这个问题,我们需要为Kubernetes的就绪性探针和存活性探针配置一个初始延迟时间(initialDelaySeconds)。这个参数告诉Kubernetes在容器启动后,等待指定秒数后再开始执行探针检查。这为Spring Boot应用提供了足够的时间来完成其启动和初始化过程,确保在探针开始检查时,应用已经处于可接受流量的“ACCEPTING_TRAFFIC”状态。
1. Kubernetes配置示例 (Kustomization或Deployment YAML)
在Kubernetes的部署配置中,可以通过在readinessProbe和livenessProbe下添加initialDelaySeconds来设置延迟。
使用Kustomization文件进行补丁修改:
# kustomization.yml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml # 假设你的Deployment定义在这里
patches:
- target:
kind: Deployment
name: my-app-deployment # 替换为你的Deployment名称
patch: |
- op: replace
path: /spec/template/spec/containers/0/readinessProbe/initialDelaySeconds
value: 60
- op: replace
path: /spec/template/spec/containers/0/livenessProbe/initialDelaySeconds
value: 60直接在Deployment YAML中配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: com.xyz/my-app:0.0.1-SNAPSHOT
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness # Spring Boot Actuator的就绪性端点
port: 8080
initialDelaySeconds: 60 # 容器启动后,等待60秒再开始检查就绪性
periodSeconds: 10 # 每10秒检查一次
timeoutSeconds: 5 # 探针超时时间
failureThreshold: 3 # 失败3次后认为不就绪
livenessProbe:
httpGet:
path: /actuator/health/liveness # Spring Boot Actuator的存活性端点
port: 8080
initialDelaySeconds: 60 # 容器启动后,等待60秒再开始检查存活性
periodSeconds: 10 # 每10秒检查一次
timeoutSeconds: 5 # 探针超时时间
failureThreshold: 3 # 失败3次后认为不存活2. Spring Boot应用内配置 (可选但推荐)
为了让Spring Boot应用能够正确响应Kubernetes的健康检查,需要引入spring-boot-starter-actuator依赖,并在application.yml中配置相应的健康端点。
pom.xml依赖:
org.springframework.boot spring-boot-starter-actuator
application.yml配置:
management:
endpoint:
health:
show-details: always # 建议在非生产环境开启,方便调试
probes:
enabled: true # 启用LivenessState和ReadinessState
endpoints:
web:
exposure:
include: health # 暴露健康端点如果需要进一步细化Spring Boot应用内部的就绪性判断逻辑,例如,当所有数据库连接池都初始化完毕后才报告为“就绪”,可以自定义健康指示器。
注意事项与最佳实践
- initialDelaySeconds的设置: 这个值应该根据应用的实际启动时间来确定。可以通过本地测试、查看日志中“Started MyApplication in X seconds”的时间,并在此基础上增加一个安全裕度来估算。过短可能导致问题复现,过长则会延长应用部署上线时间。
-
periodSeconds、timeoutSeconds和failureThreshold:
- periodSeconds:探针执行的频率。
- timeoutSeconds:探针请求的超时时间。
- failureThreshold:探针连续失败多少次后被判定为失败。 合理配置这些参数可以防止误判,并提高系统的响应性。
- 区分Liveness和Readiness: 存活性探针关注应用是否“活着”,就绪性探针关注应用是否“准备好接收流量”。两者目的不同,通常就绪性探针的条件会比存活性探针更严格。
- 日志监控: 部署后务必密切关注Pod的事件日志和应用容器的详细日志,以便在探针配置不当或应用本身存在其他问题时,能及时发现并进行调整。
- 平滑启动与关闭: 除了探针,还应考虑应用在接收SIGTERM信号时的平滑关闭机制,确保在Pod终止前,所有正在处理的请求都能完成,并释放资源。Spring Boot 2.3+ 默认支持优雅停机。
总结
Spring Boot应用在Kubernetes中启动后立即关闭,通常是由于Kubernetes的就绪性探针在应用尚未完全初始化时过早检查所致。通过在Kubernetes部署配置中为readinessProbe和livenessProbe设置合理的initialDelaySeconds,可以为应用提供充足的启动时间。结合Spring Boot Actuator的健康端点,确保应用能够正确响应Kubernetes的健康检查,是保障应用在云原生环境中稳定运行的关键。正确配置这些探针,不仅能解决启动问题,还能提升应用的韧性和用户体验。










