欢迎访问我的 GitHub
https://github.com/zq2599/blog_demos
- 内容:原创分类汇总及配套源码,涉及 Java、Docker、K8S、DevOPS 等
关于《SpringBoot-2.3 容器化技术》系列
- 《SpringBoot-2.3 容器化技术》系列,旨在和大家一起学习实践 2.3 版本带来的最新容器化技术,让咱们的 Java 应用更加适应容器化环境,在云计算时代依旧紧跟主流,保持竞争力;
- 全系列文章分为主题和辅助两部分,主题部分如下:
- 《体验 SpringBoot(2.3) 应用制作 Docker 镜像 (官方方案)》;
- 《详解 SpringBoot(2.3) 应用制作 Docker 镜像 (官方方案)》;
- 《掌握 SpringBoot-2.3 的容器探针:基础篇》;
- 《掌握 SpringBoot-2.3 的容器探针:深入篇》;
- 《掌握 SpringBoot-2.3 的容器探针:实战篇》;
- 辅助部分是一些参考资料和备忘总结,如下:
- 《SpringBoot-2.3 镜像方案为什么要做多个 layer》;
- 《设置非 root 账号不用 sudo 直接执行 docker 命令》;
- 《开发阶段,将 SpringBoot 应用快速部署到 K8S》;
前文回顾
- 本文是《掌握 SpringBoot-2.3 的容器探针》系列的第二篇,前文《掌握 SpringBoot-2.3 的容器探针:基础篇》知道了 kubernetes 的存活和就绪探针,以及 SpringBoot-2.3 的 actuator 新增的两个 endpoint,当我们把应用部署到 kubernetes 环境时,这些知识让我们能配置出官方推荐的探针方案,如下图:
- 尽管上述配置已经可以覆盖多数场景,依然有三个问题未解决:
- 首先,SpringBoot 为 kubernetes 提供了两个 actuator 项,但是那些并未部署在 kubernetes 的 SringBoot 应用呢?用不上这两项也要对外暴露这两个服务地址吗?
- 其次,就绪探针是什么时候开始返回 200 返回码的?应用启动阶段,业务服务可能需要一段时间才能正常工作,就绪探针要是提前返回了 200,那 k8s 就认为容器可以正常工作了,这时候把外部请求调度过来是无法正常响应的,所以搞清楚就绪探针的状态变化逻辑很重要;
- 最后,也是最重要的一点:有的场景下,例如外部依赖服务异常、本地全局异常等情况下,业务不想对外提供服务,等到问题解决后业务又可以对外提供服务了,如果此时我们能自己写代码控制就绪探针的返回码,那就做到了控制 kubernetes 是否将外部请求调度到此容器上,这可是个很实用的功能!
本篇就是为了解决上述问题而作,这些问题解决后才能用好探针技术,让它在容器环境带来更大价值;
关键知识点
解决上述问题的关键集中在以下几个知识点:
- SpringBoot 对容器环境的判断;
- SpringBoot 对状态定义;
- 获取状态;
- 监听状态;
- 修改状态;
接下来挨个学习这些知识点;
SpringBoot 对容器环境的判断
- 官方文档如下图所示,SpringBoot 判断是否是 kubernetes 环境的逻辑很简单:是否有 <font color=”blue”>_SERVICE_HOST</font> 和 <font color=”blue”>_SERVICE_PORT</font> 这两个环境变量:
- 熟悉 kubernetes 的读者看到 <font color=”blue”>_SERVICE_HOST”</font> 和 <font color=”blue”>_SERVICE_PORT</font>,应该会想起 <font color=”red”>KUBERNETES_SERVICE_HOST</font> 和 <font color=”blue”>KUBERNETES_SERVICE_PORT</font>,这是 k8s 给 pod 中配置的环境变量,看来 SpringBoot 也是针对 k8s 的这个规则来判定是否是容器环境的 (如果将来 k8s 的某个版本不给 pod 设置这个环境变量,那些原本可以正常运行的 pod 岂不是有危险了?);
- 接下来通过实践来验证上述规则是否有效;
- 创建一个 SpringBoot-2.3.0.RELEASE 的应用,其 pom.xml 中的 parent 信息如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>
- 增加 actuator 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 启动该应用,浏览器访问:<font color=”blue”>http://localhost:8080/actuator/health/liveness</font>,返回 404 错误:
- 以上返回是符合预期的,因为此时并非在 kubernetes 环境,接下来将 ”<font color=”blue”>_SERVICE_HOST</font> 和 <font color=”blue”>_SERVICE_PORT</font> 这两个环境变量加入应用进程,看看是否有变化;
- 如下图,编辑启动类的配置信息:
- 点击下图红框位置,即可进入编辑环境变量的窗口:
- 新的窗口中,操作如下图红框中所示,新增了两个环境变量:
- 再次运行程序,这次返回的状态码是 200:
- 至此,我们弄明白了 SpringBoot 是否开启探针的逻辑,即应用是否运行在容器环境,而是否是容器环境的判定逻辑则是 <font color=”blue”>_SERVICE_HOST</font> 和 <font color=”blue”>_SERVICE_PORT</font> 这两个环境变量是否存在;
非 kubernetes 环境开启探针
<font color=”blue”>/actuator/health/liveness</font> 和 <font color=”blue”>/actuator/health/readiness</font> 在 kubernetes 环境才会开启,但是一般情况下,在开发阶段 SpringBoot 应用可能运行在自己的电脑上,此时如果想查看这两个接口的返回值有两种方式:
第一种,就是前面提到的添加 <font color=”blue”>_SERVICE_HOST</font> 和 <font color=”blue”>_SERVICE_PORT</font> 这两个环境变量,让 SpringBoot 以为当前环境是 kubernetes 环境;
第二种,是按照官方指导添加属性,如下图红框所示:
SpringBoot 对探针相关状态定义
- 首先要弄清楚有哪些状态,源码是最准确的;
- 如下图,存活探针一共有两种状态:<font color=”blue”>CORRECT</font> 表示应用运行中并且内部状态正常,<font color=”blue”>BROKEN</font> 表示应用运行中并且内部是 BROKEN 状态 (请原谅我的英语水平)
- 如下图,就绪探针一共有两种状态:<font color=”blue”>ACCEPTING_TRAFFIC</font> 表示应用可以对外提供服务,<font color=”blue”>REFUSING_TRAFFIC</font> 表示应用无法对外提供服务;
- 另外,上图的 since 注解显示这两个枚举是从 <font color=”red”>2.3.0</font> 版本开始生效的;
- 小小八卦一下,上述两个枚举的作者 <font color=”blue”>Brian Clozel</font>,坐标法国里昂,目前在 sringboot 的提交次数排第 8 名:
- 在 SpringBoot 启动过程中,应用、存活探针、就绪探针三者状态对应关系如下图:
- 在 SpringBoot 停止过程中,应用、存活探针、就绪探针三者状态对应关系如下图:
获取状态
如果业务应用想获取当前的存活和就绪状态,将 ApplicationAvailability 接口 autowire 进来即可,下一篇《实战篇》会有详细的使用方式,这里看下关键代码:
监听状态
得益于 Spring 完整的事件发布和订阅机制,业务应用通过 EventListener 注解就能监听到存活和就绪状态的变化,在 EventListener 注解修饰的方法中写入必要的业务代码即可实现状态监听,下一篇《实战篇》会有详细的使用方式,这里看下关键代码:
修改状态
- 修改状态,尤其是就绪状态,这应该是我们最关注的功能了,在某些业务场景下,应用无法对外提供服务,这时候我们希望 K8S 不要将外部请求调度到这里,如果 K8S 通过就绪探针收到返回码非 200,就不再将请求调度到这个 pod 上;
- 下一篇《实战篇》会有详细的代码介绍,这里给出关键代码作为参考:
请注意
重要的事情一定要强调:咱们修改状态的最终目的,不是为了取得 applicationAvailability.getReadinessState() 返回新的枚举对象,而是要 <font color=”red”> 改变 /actuator/health/readiness 接口的返回码 ( 就绪是 200,未就绪是 503)</font>,这是 kubernetes 的探针规则要用到的;
为啥都放在下一篇
- 文章看到这里您可能已经火冒三丈了:关键代码都贴出来了,为啥不在本章给出完整源码?骗点击量?凑字数?凑文章数?
- 存活和就绪探针是在 kubernetes 环境下的工具,为了给您提供尽量准确和完整的参考,所有的代码和操作都必须在 kubernetes 环境完成调试才能发布,而且这些操作应该作为单独章节,与当前的理论知识分开;
- 欢迎进入《实战篇》,随 SpringBoot-2.3.0.RELEASE,一起在 kubernetes 世界畅游;
欢迎关注我的公众号:程序员欣宸
https://github.com/zq2599/blog_demos