Spring Boot 是常用 Java 微服务框架之一。Spring Cloud 拥有一组丰富的、良好集成的 Java 类库,用于应对 Java 应用程序堆栈中发生的运行时问题;而 Kubernetes 则提供了丰富的功能集来运行多语言微服务。这些技术彼此互补,为 Spring Boot 应用程序提供了强大的平台。
本文不是讲述如何将Spring Boot 程序部署到Kubernetes中,网上已经有大量的部署实践文章,大家有兴趣的可以查阅。主要讲述Spring Boot社区为了进一步简化和规范Spring Boot on k8s而做出的一些功能增强。大家完全可以将这些新功能实践到自己项目中。
Liveness 和 Readiness
首先我们简单介绍一下,kubernetes 中 Liveness 和 Readiness的含义。
在Kubernetes中,Liveness 和 Readiness代表了应用程序状态的各个方面。
应用程序的Liveness状态表明内部状态是否有效,如果Liveness 失败,则意味着应用程序本身处于故障状态并且无法从中恢复,在这种情况下,最佳的操作方法是重新启动应用程序例如,如果本地缓存已损坏且无法修复,则依赖本地缓存的应用程序应使其Liveness检测失败。
Readiness状态告诉应用程序是否准备好接受客户端请求;如果Readiness状态尚未就绪,则Kubernetes不应将流量路由到该实例;如果应用程序正忙于处理任务队列,则它可以将自己声明为繁忙,直到其执行负载可以再次管理。
那么接下来我们看下Spring Boot怎么支持Liveness 和 Readiness。
Liveness 和 Readiness 成为 Spring Boot 核心概念
Liveness 和 Readiness概念不仅适用于Kubernetes,而且无论部署平台如何,它们通常都有用。引入了LivenessState
和ReadinessState
,它们是这些概念的不可变表示形式。您可以随时从ApplicationAvailability
中获取它们:
// Available as a component in the application context
ApplicationAvailability availability;
LivenessState livenessState = availabilityProvider.getLivenessState();
ReadinessState readinessState = availabilityProvider.getReadinessState()
通过轮询,获取应用程序的状态是不完整的。只有应用程序知道其生命周期(启动,关闭),或者可以提供有关运行时错误的上下文(在处理任务时以中断状态结束)。Spring Boot应用程序上下文在应用程序的生命周期内发布这些事件,您的应用程序代码也应对此做出适配。
这就是为什么我们选择使用Spring Application Event模型来更改可用性状态并监听更新的原因:
/**
* Component that checks that the local cache is in a valid state.
*/
@Component
public class LocalCacheVerifier {
private final ApplicationEventPublisher eventPublisher;
public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void checkLocalCache() {
try {
//...
}
catch (CacheCompletelyBroken ex) {
AvailabilityChangeEvent.publish(this.eventPublisher, LivenessState.BROKEN);
}
}
}
组件还可以使用@EventListener
监听这些事件(或通过实现ApplicationListener
)。请查阅参考文档以获取更多信息。
该支持直接与spring-boot
模块一起提供,并已为所有Spring Boot应用程序激活;这使其可用于所有类型的应用程序(Web,批处理等),并允许您实现不一定与HTTP绑定的探针。
使用Spring Boot Actuator公开Kubernetes探针
可能会对一个非常常见的用例感兴趣:在Kubernetes上部署Web应用程序并配置HTTP探针,将Spring Boot Actuator依赖项添加到您的应用程序是唯一的要求!Actuator将使用Health支持配置Liveness和Readiness HTTP探针。
Actuator将从ApplicationAvailability
收集“Liveness”和“Readiness”信息,并将其用于专用的健康指标:LivenessStateHealthIndicator
和ReadinessStateHealthIndicator
。这些指标将暴露在"/actuator/health"
路径上。如果需要进一步了解“Liveness”和“Readiness”信息,可以通过"/actuator/health/liveness"
和 "/actuator/health/readiness"
访问获得。
在Kubernetes上运行的应用程序将显示以下运行状况报告:
// http://localhost:8080/actuator/health
// HTTP/1.1 200 OK
{
"status": "UP",
"components": {
"diskSpace": {
"status": "UP",
"details": { //...
}
},
"livenessProbe": {
"status": "UP"
},
"ping": {
"status": "UP"
},
"readinessProbe": {
"status": "UP"
}
},
"groups": [
"liveness",
"readiness"
]
}
调用Liveness组时,Kubernetes将获得以下信息:
// http://localhost:8080/actuator/health/liveness
// HTTP/1.1 200 OK
{
"status": "UP",
"components": {
"livenessProbe": {
"status": "UP"
}
}
}
标记为未就绪的应用程序将为“就绪”组报告以下内容:
// http://localhost:8080/actuator/health/readiness
// HTTP/1.1 503 SERVICE UNAVAILABLE
{
"status": "OUT_OF_SERVICE",
"components": {
"readinessProbe": {
"status": "OUT_OF_SERVICE"
}
}
}
HTTP探针仅针对Kubernetes上运行的应用程序进行配置。您可以通过使用management.health.probes.enabled = true
配置属性手动启用探针在本地进行尝试。由于探针是运行状况组,因此您将获得许多其他功能例如配置HTTP状态映射器,安全性,详细信息可见性…
当然,您可以将其他运行状况指示器配置为探针的一部分,以检查外部系统的状态:数据库,Web API,共享缓存。给定现有的CacheCheckHealthIndicator
,您可以使用以下方法扩充活动性探针:
management.endpoint.health.group.liveness.include=livenessProbe,cacheCheck
Graceful shutdown
由于运行在Kubernetes中的Pod存在动态的特性,这就要求我们的应用程序要做相应的适配。优雅关闭就是其中重要的一个。需要应用程序监听SIGTERM信号,停止接受新的链接,处理已有的链接等等。此时框架提供了该功能,那么我们的业务代码可以更加简单。
下面讲了Spring boot 框架是怎么实现的?
所有四个嵌入式Web服务器(Jetty,Reactor Netty,Tomcat和Undertow)以及基于响应的和基于Servlet的Web应用程序都支持正常关闭。启用后,应用程序关闭将包括可配置持续时间的宽限期。宽限期内,现有请求将被允许完成,但新请求将被禁止。不允许新请求的确切方式因所使用的Web服务器而异,Jetty,Reactor Netty和Tomcat将停止接受请求Undertow将接受请求,但会立即以服务不可用(503)响应进行响应。
正常关闭是在应用程序关闭处理期间以及销毁任何Bean之前的第一步,这确保了允许在运行中请求完成时发生的任何处理都可以使用这些Bean。 配置server.shutdown.grace-period
属性,如以下示例所示:
server.shutdown.grace-period=30s
理论上该值应该和Kubernetes 部署yaml中的terminationGracePeriodSeconds
设定的值相等。
当然除了这两个比较重要的特性,还有Docker镜像创建这个点,感兴趣的可以去了解一下,这里不再阐述。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。