掌握SpringBoot-2.3的容器探针:深入篇
欢迎访问我的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的容器探针》系列的第二篇,前文 《掌握SpringBoot-2.3的容器探针:基础篇》知道了kubernetes的存活和就绪探针,以及SpringBoot-2.3的actuator新增的两个endpoint,当我们把应用部署到kubernetes环境时,这些知识让我们能配置出官方推荐的探针方案,如下图:
- 尽管上述配置已经可以覆盖多数场景,依然有三个问题未解决:
首先,SpringBoot为kubernetes提供了两个actuator项,但是那些并未部署在kubernetes的SringBoot应用呢?用不上这两项也要对外暴露这两个服务地址吗?
其次,就绪探针是什么时候开始返回200返回码的?应用启动阶段,业务服务可能需要一段时间才能正常工作,就绪探针要是提前返回了200,那k8s就认为容器可以正常工作了,这时候把外部请求调度过来是无法正常响应的,所以搞清楚就绪探针的状态变化逻辑很重要;
最后,也是最重要的一点:有的场景下,例如外部依赖服务异常、本地全局异常等情况下,业务不想对外提供服务,等到问题解决后业务又可以对外提供服务了,如果此时我们能自己写代码控制就绪探针的返回码,那就做到了控制kubernetes是否将外部请求调度到此容器上,这可是个很实用的功能!
本篇就是为了解决上述问题而作,这些问题解决后才能用好探针技术,让它在容器环境带来更大价值;
关键知识点
解决上述问题的关键集中在以下几个知识点:
- SpringBoot对容器环境的判断;
- SpringBoot对状态定义;
- 获取状态;
- 监听状态;
- 修改状态;
接下来挨个学习这些知识点;
SpringBoot对容器环境的判断
官方文档如下图所示,SpringBoot判断是否是kubernetes环境的逻辑很简单:是否有_SERVICE_HOST和_SERVICE_PORT这两个环境变量:
熟悉kubernetes的读者看到_SERVICE_HOST" 和_SERVICE_PORT,应该会想起KUBERNETES_SERVICE_HOST和KUBERNETES_SERVICE_PORT,这是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>
- 启动该应用,浏览器访问:http://localhost:8080/actuator/health/liveness,返回404错误:
- 以上返回是符合预期的,因为此时并非在kubernetes环境,接下来将"_SERVICE_HOST 和_SERVICE_PORT这两个环境变量加入应用进程,看看是否有变化;
- 如下图,编辑启动类的配置信息:
- 点击下图红框位置,即可进入编辑环境变量的窗口:
- 新的窗口中,操作如下图红框中所示,新增了两个环境变量:
- 再次运行程序,这次返回的状态码是200:
- 至此,我们弄明白了SpringBoot是否开启探针的逻辑,即应用是否运行在容器环境,而是否是容器环境的判定逻辑则是_SERVICE_HOST和_SERVICE_PORT这两个环境变量是否存在;
非kubernetes环境开启探针
/actuator/health/liveness和/actuator/health/readiness在kubernetes环境才会开启,但是一般情况下,在开发阶段SpringBoot应用可能运行在自己的电脑上,此时如果想查看这两个接口的返回值有两种方式:
第一种,就是前面提到的添加_SERVICE_HOST和_SERVICE_PORT这两个环境变量,让SpringBoot以为当前环境是kubernetes环境;
第二种,是按照官方指导添加属性,如下图红框所示:
SpringBoot对探针相关状态定义
- 首先要弄清楚有哪些状态,源码是最准确的;
- 如下图,存活探针一共有两种状态:CORRECT表示应用运行中并且内部状态正常,BROKEN表示应用运行中并且内部是BROKEN状态(请原谅我的英语水平)
- 如下图,就绪探针一共有两种状态:ACCEPTING_TRAFFIC表示应用可以对外提供服务,REFUSING_TRAFFIC表示应用无法对外提供服务;
另外,上图的since注解显示这两个枚举是从2.3.0版本开始生效的;
小小八卦一下,上述两个枚举的作者Brian Clozel,坐标法国里昂,目前在sringboot的提交次数排第8名:
- 在SpringBoot启动过程中,应用、存活探针、就绪探针三者状态对应关系如下图:
- 在SpringBoot停止过程中,应用、存活探针、就绪探针三者状态对应关系如下图:
获取状态
如果业务应用想获取当前的存活和就绪状态,将ApplicationAvailability接口autowire进来即可,下一篇《实战篇》会有详细的使用方式,这里看下关键代码:
监听状态
得益于Spring完整的事件发布和订阅机制,业务应用通过EventListener注解就能监听到存活和就绪状态的变化,在EventListener注解修饰的方法中写入必要的业务代码即可实现状态监听,下一篇《实战篇》会有详细的使用方式,这里看下关键代码:
修改状态
- 修改状态,尤其是就绪状态,这应该是我们最关注的功能了,在某些业务场景下,应用无法对外提供服务,这时候我们希望K8S不要将外部请求调度到这里,如果K8S通过就绪探针收到返回码非200,就不再将请求调度到这个pod上;
- 下一篇《实战篇》会有详细的代码介绍,这里给出关键代码作为参考:
请注意
重要的事情一定要强调:咱们修改状态的最终目的,不是为了取得applicationAvailability.getReadinessState()返回新的枚举对象,而是要改变/actuator/health/readiness接口的返回码(就绪是200,未就绪是503),这是kubernetes的探针规则要用到的;
为啥都放在下一篇
- 文章看到这里您可能已经火冒三丈了:关键代码都贴出来了,为啥不在本章给出完整源码?骗点击量?凑字数?凑文章数?
- 存活和就绪探针是在kubernetes环境下的工具,为了给您提供尽量准确和完整的参考,所有的代码和操作都必须在kubernetes环境完成调试才能发布,而且这些操作应该作为单独章节,与当前的理论知识分开;
- 欢迎进入《实战篇》,随SpringBoot-2.3.0.RELEASE,一起在kubernetes世界畅游;
欢迎关注我的公众号:程序员欣宸
https://github.com/zq2599/blog_demos
掌握SpringBoot-2.3的容器探针:深入篇的更多相关文章
- 掌握SpringBoot-2.3的容器探针:基础篇
欢迎访问我的GitHub 地址:https://github.com/zq2599/blog_demos 内容:原创文章分类汇总,及配套源码,涉及Java.Docker.K8S.DevOPS等 关于& ...
- 掌握SpringBoot-2.3的容器探针:实战篇
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:原创文章分类汇总,及配套源码,涉及Java.Docker.K8S.DevOPS等 经过多篇知识 ...
- SpringBoot系列之Spring容器添加组件方式
SpringBoot系列之Spring容器添加组件方式 本博客介绍SpringBoot项目中将组件添加到Spring容器中的方法,SpringBoot项目有一个很明显的优点,就是不需要再编写xml配置 ...
- K8S容器探针
容器探针 探针是由 kubelet对容器执行的定期诊断.要执行诊断, kubelet 调用由容器实现的 Handler .有三种类型的处理程序: ExecAction :在容器内执行指定命令 ...
- SpringBoot(七) -- 嵌入式Servlet容器
一.嵌入式Servlet容器 在传统的开发中,我们在完成开发后需要将项目打成war包,在外部配置好TomCat容器,而这个TomCat就是Servlet容器.在使用SpringBoot开发时,我们无需 ...
- spring-boot内嵌三大容器https设置
spring-boot内嵌三大容器https设置 spring-boot默认的内嵌容器为tomcat,除了tomcat之前还可以设置jetty和undertow. 1.设置https spring-b ...
- Springboot以Jetty为容器实现http重定向到https
1 简介 之前讲解的Springboot整合https用的是tomcat作为容器,tomcat也是一个流行多年的老牌Java容器了.但针对不同的场景,还是会有不同的选择,如Jetty.Jetty是架构 ...
- 容器探针(liveness and readiness probe)
一.为什么需要容器探针 如何保持Pod健康 只要将pod调度到某个节点,Kubelet就会运行pod的容器,如果该pod的容器有一个或者所有的都终止运行(容器的主进程崩溃),Kubelet将重启容 ...
- 基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇
前提 前置文章: Github Page:<基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> Coding Page:<基于Netty和SpringBoot实现 ...
随机推荐
- bash leetcode
拓展:grep 193. ref: https://blog.csdn.net/yanglingwell/article/details/82343407 Given a text file fil ...
- react-debug
最近练习react的时候遇到一些问题: 在redux模式下,同一个api依据参数获取不同data的时候,返回的data相同 原因:多次调用该接口时,action的type相同,导致对应于该接口的每个r ...
- Oracle百万数据查询语句
SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT id, name, age, birthDate, sex, describe, city, cre ...
- 13.3 Go章节练习题
13.3 Go章节练习题 练习1:定义1个整数,1个小数,访问变量,打印数值和类型,更改变量的数值,打印数值 练习2:同时定义3个整数, 练习3:同时定义3个字符串 练习4:定义变量后,没有初始值,直 ...
- dockerfile定制docker的脚本文件
Dockerfile文件详解 #指定操作系统 FROM scratch #制作base image 基础镜像,尽量使用官方的image作为base image FROM centos #使用base ...
- 使用脚手架 vue-cli 4.0以上版本创建vue项目
1. 什么是 Vue CLI 如果你只是简单写几个Vue的Demo程序, 那么你不需要Vue CLI:如果你在开发大型项目, 那么你需要, 并且必然需要使用Vue CLI. 使用Vue.js开发大型应 ...
- 201771010128王玉兰《面向对象与程序设计(java)第十五周学习总结》
第一部分:理论知识 一:JAR文件 Java程序的打包:程序编译完成后,程序员 将.class文件压缩打包为.jar文件后,GUI界面 程序就可以直接双击图标运行. jar文件(Java归档)既可以包 ...
- 基于腾讯云搭建squid代理服务器
本文主要介绍下在腾讯云上搭建squid代理服务器,用于访问国外网站或者为爬虫提供代理ip,以及简单介绍下如何基于腾讯云提供的SDK,批量开启或者销毁代理服务器实例. Squid是一个高性能的代理缓存服 ...
- 解决python引包错误
# coding=utf8# date = 2019/12/23 19:54# 清白丶之年__照林""" # Solve Import Lib Error Add Som ...
- DQN(Deep Q-learning)入门教程(二)之最优选择
在上一篇博客:DQN(Deep Q-learning)入门教程(一)之强化学习介绍中有三个很重要的函数: 策略:\(\pi(a|s) = P(A_t=a | S_t=s)\) 状态价值函数:\(v_\ ...