记一次k8s健康检查导致的问题
是什么原因导致正在运行的容器,PaaS平台是有事件日志的,当时忘记截图了(盘的时候查不到了)... 记得当时有http超时事件,也有状态码为503的事件。例如,提供基本的应用程序运行状况信息的 health 端点。像我们引入DB依赖,Nacos依赖啥的,这些依赖实现了Actuator的health策略接口。Actuator是Springboot的一个模块,模块提供了Spring Boot的所有生产
问题背景
手机收到一条告警短信,线上环境接口出现异常了!!!告警内容是某一个对外服务API状态码异常,状态码为500。好家伙第一反应去PaaS平台(KuberSphere)查看,发现该服务的一个pod正在重启,并且重启完后又继续重启。就在这时又收到一条告警恢复短信(大概在告警短信一分钟后),状态码为200了。。。这篇文章来盘一下这次问题。
k8s健康检查
k8s探针
k8s探针 是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类型的处理程序:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- CPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
k8s健康检查 探针
- livenessProbe(存活探针):用于判断容器是否存活(Running状态),如果livenessProbe探针探测到容器不健康,则 kubelet 将 “杀掉” 该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含livenessProbe探针,那么 kubelet 认为该容器的 livenessProbe探针 返回的值永远是Success。
- readinessProbe(就绪探针):用于判断容器服务是否可用(Ready状态),达到Ready状态的Pod才可以接收请求。对于被Service管理的Pod、Service与PodEndpoint的关联关系也将基于Pod是否Ready进行设置。如果在运行过程中Ready 状态变为False,则系统自动将其从Service的后端Endpoint列表中隔离出去,后续再把恢复到Ready状态的Pod加回后端Endpoint列表。
- startupProbe(启动探针):如果配置了startupProbe,就会先禁止其他的探测,直到它成功为止,成功后将不再进行探测。比较适用于容器启动时间长的场景。需要 kubernetes 版本 v1.18 或以上。
问题定位
我们配置的健康检查如下:
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 90
timeoutSeconds: 3
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 90
timeoutSeconds: 3
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
复制代码
这里边有些配置含义如下:
配置 | 含义 |
---|---|
httpGet.path | get请求路径 |
httpGet.port | get请求端口 |
httpGet.scheme | get请求协议 |
initialDelaySeconds | 初始延迟(秒),在检查其运行状况之前,容器启动后需要等待多长时间。 |
timeoutSeconds | 超时时间(秒),等待探针完成多长时间。如果超过时间,则认为探测失败。默认为1秒。最小值为1。 |
periodSeconds | 执行探测频率(秒),执行探测的频率(以秒为单位)。默认为10秒。最小值为1。 |
successThreshold | 健康阈值,探测失败后,连续最小成功探测为成功。默认值为1。最小值为1。存活探针和启动探针内必须为1。 |
failureThreshold | 不健康阈值,探针进入失败状态时需要连续探测失败的最小次数。 |
公司提供的配置文档中不包含启动探针的配置,猜测是部署的k8s的版本还不支持启动探针。
问题背景中我们抽出来几个 关键点:
- 一个pod正在重启。
- pod重启完成后又继续重启。
- 告警短信大概一分钟后告警恢复。
到这里可以联想到,存活探针发送get请求获取到的响应的状态码不在 200 和 400之间或者直接超时,所以容器重启直接影响服务,告警通知;但是配置的初始延迟为90秒太短导致一直重启;就在这时就绪探针判断 Ready 状态变为False,则系统自动将其从 Service 的后端 Endpoint 列表中隔离出去,故障 pod 排除掉之后,告警恢复。
是什么原因导致正在运行的容器,PaaS平台是有事件日志的,当时忘记截图了(盘的时候查不到了)... 记得当时有http超时事件,也有状态码为503的事件。超时可能是网络波动或者大概率是初始延迟设置过短。那么这个503状态码到底是为什么呢?
Actuator
Actuator是Springboot的一个模块,模块提供了Spring Boot的所有生产就绪功能。
Endpoints
Actuator 端点允许您监视应用程序并与之交互。 Spring Boot 包括许多内置端点,并允许您添加自己的端点。 例如,提供基本的应用程序运行状况信息的 health 端点。
Actuator的health端点
我们配置健康检查用的接口就是Actuator提供的 health 端点接口。像我们引入DB依赖,Nacos依赖啥的,这些依赖实现了Actuator的health策略接口HealthIndicator
,请求health端点的时候就会调用策略实现类检查健康状况。
health端点的返回会返回一个status,可以通过配置management.endpoint.health.show-details=always
设置返回详细信息。
下边是一个详细信息的返回值。
{
"components":{
"db":{
"components":{
"dataSource":{
"details":{
"database":"MySQL",
"result":1,
"validationQuery":"/* ping */ SELECT 1"
},
"status":{
"code":"UP",
"description":""
}
},
"dataSource2":{
"details":{
"database":"MySQL",
"result":1,
"validationQuery":"/* ping */ SELECT 1"
},
"status":{
"code":"UP",
"description":""
}
}
},
"status":{
"code":"UP",
"description":""
}
},
"discoveryComposite":{
"components":{
"discoveryClient":{
"details":{
"services":[
"***",
"***",
"***-gateway"
]
},
"status":{
"code":"UP",
"description":""
}
}
},
"status":{
"code":"UP",
"description":""
}
},
"diskSpace":{
"details":{
"total":"528309530624",
"free":"463192977408",
"threshold":10485760
},
"status":{
"code":"UP",
"description":""
}
},
"mail":{
"details":{
"location":"10.************:25"
},
"status":{
"code":"UP",
"description":""
}
},
"ping":{
"details":{
},
"status":{
"code":"UP",
"description":""
}
},
"refreshScope":{
"details":{
},
"status":{
"code":"UP",
"description":""
}
}
},
"groups":[
],
"status":{
"code":"UP",
"description":""
}
}
复制代码
返回的Status的code编码有四种。
/**
* 指示组件或子系统处于未知状态。
*/
public static final Status UNKNOWN = new Status("UNKNOWN");
/**
* 指示组件或子系统按预期运行。
*/
public static final Status UP = new Status("UP");
/**
* 指示组件或子系统发生了意外故障。
*/
public static final Status DOWN = new Status("DOWN");
/**
* 指示组件或子系统已从服务中取出,不应再使用。
*/
public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");
复制代码
翻看源码看到了这四个编码与http状态码的关系,即 DOWN 和 OUT_OF_SERVICE 会返回http状态码 503,其他返回200状态码。
health端点如果异常,即可以通过详细信息定位到异常的组件!
更多推荐
所有评论(0)