【云原生 | 从零开始学Kubernetes】十三、k8s的容器探测以及启动探测_k8s 检测容器启动成功

存活性探测 livenessProbe 和就绪性探测 readinessProbe

livenessProbe存活性探测

许多应用程序经过长时间运行最终过渡到无法运行的状态除了重启无法恢复。通常情况下K8S 会发现应用程序已经终止然后重启应用程序 pod。有时应用程序可能因为某些原因后端服务故障等导致暂时无法对外提供服务但应用软件没有终止导致 K8S 无法隔离有故障的 pod调用者可能会访问到有故障的 pod导致业务不稳定。K8S 提供 livenessProbe 来检测容器是否正常运行并且对相应状况进行相应的补救措施。

readinessProbe就绪性探测

在没有配置 readinessProbe 的资源对象中pod 中的容器启动完成后就认为 pod 中的应用程序可以对外提供服务该 pod 就会加入相对应的 service对外提供服务。但有时一些应用程序启动后需要较长时间的加载才能对外服务如果这时对外提供服务执行结果必然无法达到预期效果影响用户体验。比如使用 tomcat 的应用程序来说并不是简单地说 tomcat 启动成功就可以 对外提供服务的还需要等待 spring 容器初始化数据库连接上等等。

目前 LivenessProbe 和 ReadinessProbe 两种探针都支持下面三种探测方法

1、ExecAction在容器中执行指定的命令如果执行成功退出码为 0 则探测成功。

2、TCPSocketAction通过容器的 IP 地址和端口号执行 TCP 检查如果能够建立 TCP 连接 则表明容器健康。

3、HTTPGetAction通过容器的 IP 地址、端口号及路径调用 HTTP Get 方法如果响应的状态码大于等于 200 且小于 400则认为容器健康

探针探测结果有以下值

1、Success表示通过检测。

2、Failure表示未通过检测。

3、Unknown表示检测没有正常进行。

Pod 探针相关的属性

探针(Probe)有许多可选字段可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为

initialDelaySeconds Pod 启动后首次进行检查的等待时间单位“秒”。

periodSeconds 检查的间隔时间默认为 10s单位“秒”。

timeoutSeconds 探针执行检测请求后等待响应的超时时间默认为 1s单位“秒”。

successThreshold连续探测几次成功才认为探测成功默认为 1在 Liveness 探针中必须为 1最小值为 1。

failureThreshold 探测失败的重试次数重试一定次数后将认为失败在 readiness 探针中Pod 会被标记为未就绪默认为 3最小值为 1

两种探针区别

ReadinessProbe 和 livenessProbe 可以使用相同探测方式只是对 Pod 的处置方式不同

readinessProbe 当检测失败后将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。

livenessProbe 当检测失败后将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。

Pod 探针使用示例

1、LivenessProbe 探针使用示例

通过 exec 方式做健康探测

[root@k8smaster node]# vim liveness-exec.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-exec
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: busybox
    args: #创建测试探针探测的文件 
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe: 
      initialDelaySeconds: 10 #延迟检测时间 
      periodSeconds: 5 #检测时间间隔 
      exec:
        command:
        - cat
        - /tmp/healthy

容器启动设置执行的命令
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600" 容器在初始化后首先创建一个 /tmp/healthy 文件然后执行睡眠命令睡眠 30 秒到时间后执行删除 /tmp/healthy 文件命令。而设置的存活探针检检测方式为执行 shell 命令用 cat 命令输出 healthy 文件的内容如果能成功执行这条命令存活探针就认为探测成功否则探测失败。在前 30 秒内由于文件存在所以存活探针探测时执行 cat /tmp/healthy 命令成功执行。30 秒后 healthy 文件被删除所以执行命令失败Kubernetes 会根据 Pod 设置的重启策略来判断是否重启 Pod。

[root@k8smaster node]# kubectl apply -f liveness-exec.yaml 
pod/liveness-exec created
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-exec           1/1     Running   0          30s
[root@k8smaster node]# kubectl exec -it liveness-exec -- /bin/sh
/ # cd /tmp/
/tmp # ls
/tmp # 
#进入容器之后发现文件被删除了
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-exec           1/1     Running   1          2m54s
#然后过一会他就重启了 rest那里是1
[root@k8smaster node]# kubectl describe pods liveness-exec
 Warning  Unhealthy  5s (x7 over 2m50s)   kubelet, k8snode2  Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
#可以在详细信息看到找不到文件

通过 HTTP 方式做健康探测

[root@k8smaster node]# vim liveness-http.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-http 
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: mydlqclub/springboot-helloworld:0.0.1
    livenessProbe: 
      initialDelaySeconds: 20 #延迟检测时间 
      periodSeconds: 5 #检测时间间隔 
      timeoutSeconds: 10  #超时时间设置 
      httpGet:
        scheme: HTTP
        port: 8081 
 		path: /actuator/health
      readinessProbe:		#就绪型探测
      initialDelaySeconds: 20
      periodSeconds: 5 
      timeoutSeconds: 10 
      httpGet:
        scheme: HTTP
        port: 8081 
        path: /actuator/health

上面 Pod 中启动的容器是一个 SpringBoot 应用其中引用了 Actuator 组件提供了 /actuator/health 健康检查地址存活探针可以使用 HTTPGet 方式向服务发起请求请求 8081 端口的 /actuator/health 路径来进行存活判断。
任何大于或等于 200 且小于 400 的代码表示探测成功,任何其他代码表示失败。如果探测失败则会杀死 Pod 进行重启操作。 
 
httpGet 探测方式有如下可选的控制字段: 
scheme: 用于连接 host 的协议默认为 HTTP。 
host要连接的主机名默认为 Pod IP可以在 http request head 中设置 host 头部。 
port容器上要访问端口号或名称。 
pathhttp 服务器上的访问 URI。 
httpHeaders自定义 HTTP 请求 headersHTTP 允许重复 headers。 

[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS             RESTARTS   AGE
liveness-http           1/1     Running            0          35s

[root@k8smaster node]# kubectl logs liveness-http | grep 8081
2022-07-10 19:04:19.392  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2022-07-10 19:04:19.510  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2022-07-10 19:04:37.453  INFO 1 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat-1].[localhost].[/]     : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-10 19:04:37.453  INFO 1 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-07-10 19:04:37.458  INFO 1 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

[root@k8smaster node]# curl http://10.244.1.7:8081/actuator/health
{"status":"UP"}
[root@k8smaster node]# curl -I http://10.244.1.7:8081/actuator/health
HTTP/1.1 200 
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 10 Jul 2022 11:08:55 GMT
#返回200状态码启动成功

通过 TCP 方式做健康探测

[root@k8smaster node]# vim liveness-tcp.yaml 
apiVersion: v1
kind: Pod 
metadata: 
  name: liveness-tcp 
  labels:
    app: liveness
spec: 
  containers:
  - name: liveness
    image: nginx
    livenessProbe: 
      initialDelaySeconds: 15 
      periodSeconds: 20   
	  tcpSocket: 
        port: 80

TCP 检查方式和 HTTP 检查方式非常相似在容器启动 initialDelaySeconds 参数设定的时间后kubelet 将发送第一个 livenessProbe 探针尝试连接容器的 80 端口如果连接失败则将杀死 Pod 重启容器。 

[root@k8smaster node]# kubectl apply -f liveness-tcp.yaml 
pod/liveness-tcp created
[root@k8smaster node]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
liveness-tcp            1/1     Running   0          19s

2、ReadinessProbe 探针使用示例

Pod 的 ReadinessProbe 探针使用方式和 LivenessProbe 探针探测方法一样也是支持三种只是一个是用于探测应用的存活一个是判断是否对外提供流量的条件。比如Springboot 项目设置 ReadinessProbe 探测 SpringBoot 项目的 8081 端口下的 /actuator/health 接口如果探测成功则代表内部程序以及启动就开放对外提供接口访问否则内部应用没有成功启动暂不对外提供访问直到就绪探针探测成功。

两个也可以一起用。

[root@k8smaster node]# vim readiness-exec.yaml 
apiVersion: v1
kind: Service
metadata:
  name: springboot 
  labels:
    app: springboot
spec:
  type: NodePort
  ports:
  - name: server 
    port: 8080
    targetPort: 8080
    nodePort: 31180
  - name: management  
    port: 8081
    targetPort: 8081
    nodePort: 31181
  selector:
    app: springboot
--- 
apiVersion: v1 
kind: Pod 
metadata: 
  name: springboot
  labels:
    app: springboot
spec: 
  containers:
  - name: springboot
    image: mydlqclub/springboot-helloworld:0.0.1
    ports: 
    - name: server
      containerPort: 8080
    - name: management
      containerPort: 8081
    readinessProbe:
      initialDelaySeconds: 20
      periodSeconds: 5
      timeoutSeconds: 10
      httpGet:
        scheme: HTTP
        port: 8081
        path: /actuator/health
[root@k8smaster node]# kubectl apply -f readiness-exec.yaml 
service/springboot created
pod/springboot created
[root@k8smaster node]# kubectl get pods -o wide | grep springboot
springboot              1/1     Running   0          42s     10.244.1.9    k8snode2   <none>          

pod的启动探测

Kubernetes 的三种探针

livenessProbe用于探测容器是否运行。如果存活探测失败则 kubelet 会杀死容器并且容器将受到其重启策略的影响决定是否重启。如果容器不提供存活探针则默认状态为 Success。

readinessProbe一般用于探测容器内的程序是否健康容器是否准备好服务请求。如果就绪探测失败endpoint 将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪 状态默认为 Failure。如果容器不提供就绪探针则默认状态为 Success。

startupProbe: 探测容器中的应用是否已经启动。如果提供了启动探测(startup probe)则禁用所有其他探测直到它成功为止。如果启动探测失败kubelet 将杀死容器容器服从其重启策略进行重启。 如果容器没有提供启动探测则默认状态为成功 Success。

可以自定义在 pod 启动时是否执行这些检测如果不设置则检测结果均默认为通过如果设置 则顺序为 startupProbe>readinessProbe>livenessProbe。

为什么要用 startupProbe

在 k8s 中通过控制器管理 pod如果更新 pod 的时候会创建新的 pod删除老的 pod但是如果新的 pod 创建了pod 里的容器还没完成初始化老的 pod 就被删除了会导致访问 service 或者 ingress 时候访问到的 pod 是有问题的所以 k8s 就加入了一些存活性探针livenessProbe、就绪性探针 readinessProbe 以及启动探针 startupProbe。

startupProbe 是在 k8s v1.16 加入了 alpha 版官方对其作用的解释是 
 
Indicates whether the application within the Container is started. All other probes are disabled if a startup probe is provided, until it succeeds. If the startup probe fails, the kubelet kills the Container, and the Container is subjected to its restart policy. If a Container does not provide a startup probe, the default state is Success

翻译判断容器内的应用程序是否已启动。如果提供了启动探测则禁用所有其他探测直到它成功为止。如果启动探测失败kubelet 将杀死容器容器将服从其重启策略。如果容器没有提供启动探测则默认状态为成功。

注意不要将 startupProbe 和 readinessProbe 混淆。

什么时候会用 startupProbe 呢

正常情况下我们会在 pod template 中配置 livenessProbe 来探测容器是否正常运行如果异常则会触发 restartPolicy 重启容器因为默认情况下 restartPolicy 设置的是 always

livenessProbe: 
  httpGet: 
    path: /test 
    prot: 80 
  failureThreshold: 1 
  initialDelay10 
  periodSeconds: 10 

上面配置的意思是容器启动 10s 后每 10s 检查一次允许失败的次数是 1 次。如果失败次数超过 1 则会触发 restartPolicy。

但是有时候会存在特殊情况比如服务 A 启动时间很慢需要 60s。这个时候如果还是用上面的探针就会进入死循环因为上面的探针 10s 后就开始探测这时候我们服务并没有起来发现探测失败就会触发 restartPolicy。这时候有的朋友可能会想到把 initialDelay 调成 60s 不就可以了但是我们并不能保证这个服务每次起来都是 60s假如新的版本起来要 70s甚至更多的时间我们就不好控制了。有的朋友可能还会想到把失败次数增加比如下面配置

livenessProbe: 
  httpGet: 
    path: /test 
    prot: 80 
  failureThreshold: 5 
  initialDelay60 
  periodSeconds: 10

这在启动的时候是可以解决我们目前的问题但是如果这个服务挂了呢如果 failureThreshold=1 则 10s 后就会报警通知服务挂了如果设置了 failureThreshold=5那么就需要 5*10s=50s 的时间在现在大家追求快速发现、快速定位、快速响应的时代是不被允许的。

在这时候我们把 startupProbe 和 livenessProbe 结合起来使用就可以很大程度上解决我们的问题。

livenessProbe: 
  httpGet: 
    path: /test 
    prot: 80 
  failureThreshold: 1 
  initialDelay10 
  periodSeconds: 10 
startupProbe: 
  httpGet: 
    path: /test 
    prot: 80 
  failureThreshold: 10 
  initialDelay10 
  periodSeconds: 10

上面的配置是只有 startupProbe 探测成功后再交给 livenessProbe。我们 startupProbe 配置的是 10*10s也就是说只要应用在 100s 内启动都是 OK 的而且应用挂掉了 10s 就会发现问题。

其实这种还是不能确定具体时间只能给出一个大概的范围。我个人认为对服务启动时间的影响因素太多了有可能是应用本身有可能是外部因素比如主机性能等等。我们只有在最大程度上追求高效、 稳定但是我们不能保证 100%稳定所以我们自己要做好监控有效性告警的及时性响应的快速性处理的高效性。

K8s 的 LivenessProbe 和 ReadinessProbe 的启动顺序问题

LivenessProbe 会导致 pod 重启ReadinessProbe 只是不提供服务。我们最初的理解是 LivenessProbe 会在 ReadinessProbe 成功后开始检查但事实并非如此。

kubelet 使用存活探测器来知道什么时候要重启容器。例如存活探测器可以捕捉到死锁应用程序在运行但是无法继续执行后面的步骤。这样的情况下重启容器有助于让应用程序在有问题的情况下可用。

kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量 当一个 Pod 内的所有容器都准备好了才能把这个 Pod 看作就绪了这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端在 Pod 还没有准备好的时候会从 Service 的负载均衡器中被剔除的。

kubelet 使用启动探测器(startupProbe)可以知道应用程序容器什么时候启动了。如果配置了这类探测器就可以控制容器在启动成功后再进行存活性和就绪检查确保这些存活就绪探测器不会影响应用程序的启动。这可以用于对慢启动容器进行存活性检测避免它们在启动运行之前就被杀掉。

真正的启动顺序

官方文档Caution: Liveness probes do not wait for readiness probes to succeed. If you want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe.

也就是 Liveness probes 并不会等到 Readiness probes 成功之后才运行根据上面的官方文档Liveness 和 readiness 应该是某种并发的关系。

写在最后

创作不易如果觉得内容对你有帮助麻烦给个三连关注支持一下我如果有错误请在评论区指出我会及时更改
目前正在更新的系列从零开始学k8s
感谢各位的观看文章掺杂个人理解如有错误请联系我指出~
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: k8s

“【云原生 | 从零开始学Kubernetes】十三、k8s的容器探测以及启动探测_k8s 检测容器启动成功” 的相关文章