天天看点

Kubernetes 健康检查之 livenessProbe/readinessProbe

Kubernetes 健康检查之 livenessProbe/readinessProbe

健康检查

Kubernetes 健康检查之 livenessProbe/readinessProbe

它有可能还在做初始化,这就意味着在初始化的应用进程还不能接受网络流量,所以要去控制一下pod的状态,也就是我还没有就绪,我还不能够接受流量。

有些应用跑着跑着没有响应,出现大量的503,应用实例以及不能够正常工作了,是否需要帮你重启。

tcp stocket  查看某个端口,比如某个应用跑在80端口上面,你只需要去看80端口是否是活着的,你就能够知道它是否就绪了。

但是有时候80端口启动了并不代表我业务正常了,可能应用已经死掉了,那么可以通过HTTP,任何的微服务里面都要开放healthz的健康检查的uri,我们就可以针对uri去做健康检查。

Kubernetes 健康检查之 livenessProbe/readinessProbe

如果这个文件存在,那么会返回code为0,这样就认为健康检查是通过的,如果这个文件不存在,那么这个return code为非0,也就是这次健康检查会失败。

Kubernetes 健康检查之 livenessProbe/readinessProbe

Kubernetes三种探针

k8s支持存活livenessProbe和就绪readinessProbe两种探针,两种探针都支持以下三种方式

一、exec

通过执行shell命令的方式,判断退出状态码是否是0,示例:

exec:
        command:
        - cat
        - /tmp/healthy      

二、tcp

通过TCP请求的方式,是否能建立tcp连接,示例:

tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20      

三、httpGet

通过发起http请求,判断返回结果是否符合预期,示例:

...
livenessProbe:
     httpGet:
       path: /healthz
       port: 8080
       httpHeaders:
       - name: X-Custom-Header
         value: Awesome
       initialDelaySeconds: 3
       periodSeconds: 3      
  • initialDelaySeconds指定了容器启动后多少秒后进行探测
  • periodSeconds指定每隔多少秒进行探测

Liveness 探测

Liveness 探测让用户可以自定义判断容器是否健康的条件。如果探测失败,Kubernetes 就会重启容器。还是举例说明,创建如下 Pod:启动进程首先创建文件 ​

​/tmp/healthy​

​​,30 秒后删除,在我们的设定中,如果 ​

​/tmp/healthy​

​ 文件存在,则认为容器处于正常状态,反正则发生故障。

[root@k8s-master ~]# cat liveness.yml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness-pod
  namespace: default
spec:
    restartPolicy: OnFailure
    containers:
    - name: myapp
      image: busybox
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh","-c","touch /tmp/healthy;sleep 30;rm -rf /tmp/healthy;sleep 3600"]
      livenessProbe:
        exec:
          command: ["test","-e","/tmp/healthy"]
        initialDelaySeconds: 5
        periodSeconds: 5      

​livenessProbe​

​ 部分定义如何执行 Liveness 探测:

  1. 探测的方法是:通过 test命令检查 ​

    ​/tmp/healthy​

    ​ 文件是否存在。如果命令执行成功,返回值为零,Kubernetes 则认为本次 Liveness 探测成功;如果命令返回值非零,本次 Liveness 探测失败。
  2. ​initialDelaySeconds:5 ​

    ​​指定容器启动 5s之后开始执行 Liveness 探测,我们一般会根据应用启动的准备时间来设置。比如某个应用正常启动要花 30 秒,那么 ​

    ​initialDelaySeconds​

    ​ 的值就应该大于 30。
  3. ​periodSeconds: 5​

    ​ 指定每 5 秒执行一次 Liveness 探测。Kubernetes 如果连续执行 3 次 Liveness 探测均失败,则会杀掉并重启容器。

 下面创建 Pod ​

​liveness​

​:

[root@k8s-master ~]# kubectl apply -f liveness.yml 
pod/liveness-pod created      

 从配置文件可知,最开始的 30 秒,​

​/tmp/healthy​

​​ 存在,test 命令返回 0,Liveness 探测成功,这段时间 ​

​kubectl describe pod liveness​

​​ 的 ​

​Events​

​部分会显示正常的日志。

[root@k8s-master ~]# kubectl describe pod  liveness-pod 
Events:
  Type    Reason     Age        From                 Message
  ----    ------     ----       ----                 -------
  Normal  Scheduled  <unknown>  default-scheduler    Successfully assigned default/liveness-pod to k8s-master
  Normal  Pulled     12s        kubelet, k8s-master  Container image "busybox" already present on machine
  Normal  Created    11s        kubelet, k8s-master  Created container myapp
  Normal  Started    11s        kubelet, k8s-master  Started container myapp      

35 秒之后,日志会显示 ​

​/tmp/healthy​

​ 已经不存在,Liveness 探测失败。再过几十秒,几次探测都失败后,容器会被重启。

[root@k8s-master ~]# kubectl describe pod   liveness-pod 
Command:
      /bin/sh
      -c
      touch /tmp/healthy;sleep 30;rm -rf /tmp/healthy;sleep 3600
    State:          Running
      Started:      Fri, 06 Nov 2020 15:40:59 +0800
    Last State:     Terminated
      Reason:       Error
      Exit Code:    137   #可以看到退出了,OnFailure : 容器终止运行且退出码不为0时重启
      Started:      Fri, 06 Nov 2020 15:39:45 +0800
      Finished:     Fri, 06 Nov 2020 15:40:59 +0800
    Ready:          True
    Restart Count:  1    #容器重启了1次
    Liveness:       exec [test -e /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dfmvc (ro)
Events:
  Type     Reason     Age                 From                 Message
  ----     ------     ----                ----                 -------
  Normal   Scheduled  <unknown>           default-scheduler    Successfully assigned default/liveness-pod to k8s-master
  Warning  Unhealthy  55s (x3 over 65s)   kubelet, k8s-master  Liveness probe failed:
  Normal   Killing    55s                 kubelet, k8s-master  Container myapp failed liveness probe, will be restarted  #可以看到健康检查失败
  Normal   Pulled     25s (x2 over 100s)  kubelet, k8s-master  Container image "busybox" already present on machine
  Normal   Created    25s (x2 over 99s)   kubelet, k8s-master  Created container myapp
  Normal   Started    25s (x2 over 99s)   kubelet, k8s-master  Started container myapp


[root@k8s-master ~]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE     IP            NODE         NOMINATED NODE   READINESS GATES
liveness-pod   1/1     Running   3          4m20s   10.244.0.27   k8s-master   <none>           <none>      
Kubernetes 健康检查之 livenessProbe/readinessProbe

 除了 Liveness 探测,Kubernetes Health Check 机制还包括 Readiness 探测,下篇博客见。

Pod 健康检查失败

Kubernetes 健康检查包含就绪检查(readinessProbe)和存活检查(livenessProbe) pod 如果就绪检查失败会将此 pod ip 从 service 中摘除,通过 service 访问,流量将不会被转发给就绪检查失败的 pod ,pod 如果存活检查失败,kubelet 将会杀死容器并尝试重启。

健康检查失败的可能原因有多种,除了业务程序

BUG

导致不能响应健康检查导致

unhealthy

,还能有其它原因,下面我们来逐个排查。

健康检查配置不合理

initialDelaySeconds

太短,容器启动慢,导致容器还没完全启动就开始探测,如果 successThreshold 是默认值

1

,检查失败一次就会被

kill

,然后

pod

一直这样被

kill

启。

节点负载过高

cpu

占用高(比如跑满)会导致进程无法正常发包收包,通常会

timeout

,导致

kubelet

认为

pod

不健康。

容器内进程端口监听挂掉

使用

netstat -tunlp

检查端口监听是否还在,如果不在了,抓包可以看到会直接

reset

掉健

康检查探测的连接

:

Kubernetes 健康检查之 livenessProbe/readinessProbe

连接异常,从而健康检查失败。发生这种情况的原因可能在一个节点上启动了多个使用

hostNetwork 监听相同宿主机端口的

Pod

,只会有一个

Pod

监听成功,但监听失败的

Pod

业务逻辑允许了监听失败,并没有退出, Pod

又配了健康检查,

kubelet

就会给

Pod

发送健康检查

探测报文,但 Pod

由于没有监听所以就会健康检查失败。

SYN backlog 设置过小

SYN backlog 大小即

SYN

队列大小,如果短时间内新建连接比较多,而

SYN backlog

设置太

小,就会导致新建连接失败,通过 netstat -s | grep TCPBacklogDrop

可以看到有多少是因为

backlog 满了导致丢弃的新连接。

如果确认是 backlog

满了导致的丢包,建议调高

backlog

的值,内核参数为

net.ipv4.tcp_max_syn_backlog

 ​​https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes​​

健康检查的类型

Kubernetes 为您提供两种健康检查,了解两者之间的差异及其用途非常重要。

准备就绪

就绪探测旨在让 Kubernetes 知道您的应用何时准备好为流量提供服务。Kubernetes 在允许服务向 Pod 发送流量之前确保就绪探测通过。如果就绪探测开始失败,Kubernetes 会停止向 pod 发送流量,直到它通过。

活力

Liveness probes 让 Kubernetes 知道你的应用程序是活着还是死了。如果你的应用程序还活着,那么 Kubernetes 就不会管它了。如果你的应用已经死了,Kubernetes 会移除 Pod 并启动一个新的来替换它。

健康检查如何提供帮助

让我们看一下准备情况和活跃度探针可以帮助您构建更强大的应用程序的两种情况。

准备就绪

让我们假设您的应用程序需要一分钟来预热和启动。您的服务在启动并运行之前将无法工作,即使该过程已经开始。如果您想扩展此部署以拥有多个副本,您也会遇到问题。新副本在完全准备好之前不应接收流量,但默认情况下,Kubernetes 会在容器内的进程启动后立即开始向其发送流量。通过使用就绪探测,Kubernetes 会等到应用程序完全启动后才允许服务将流量发送到新副本。

Kubernetes 健康检查之 livenessProbe/readinessProbe

活力

让我们想象另一种情况,您的应用程序有一个令人讨厌的死锁情况,导致它无限期挂起并停止服务请求。因为进程继续运行,默认情况下 Kubernetes 认为一切正常,并继续向损坏的 Pod 发送请求。通过使用活跃度探测,Kubernetes 检测到应用程序不再为请求提供服务并重新启动有问题的 pod。

Kubernetes 健康检查之 livenessProbe/readinessProbe

探头类型

下一步是定义测试就绪和活跃度的探针。有三种类型的探测:HTTP、命令和 TCP。您可以使用它们中的任何一个进行活跃度和就绪性检查。

HTTP

HTTP 探针可能是最常见的自定义活性探针类型。即使您的应用程序不是 HTTP 服务器,您也可以在应用程序内部创建一个轻量级 HTTP 服务器来响应活动探测。Kubernetes ping 一条路径,如果它收到 200 或 300 范围内的 HTTP 响应,它会将应用程序标记为健康。否则它被标记为不健康。

​​您可以在此处​​阅读有关 HTTP 探测的更多信息。

命令

对于命令探测,Kubernetes 在您的容器内运行命令。如果命令返回退出代码 0,则容器被标记为健康。否则,它被标记为不健康。当您不能或不想运行 HTTP 服务器时,这种类型的探测很有用,但可以运行可以检查您的应用程序是否健康的命令。

​​您可以在此处​​阅读有关命令探针的更多信息。

TCP

最后一种探测类型是 TCP 探测,Kubernetes 尝试在指定端口上建立 TCP 连接。如果能够建立连接,则认为容器是健康的;如果不能,则被认为是不健康的。

如果您遇到 HTTP 探测或命令探测无法正常工作的情况,TCP 探测会派上用场。例如,​​gRPC​​或 FTP 服务是此类探测的主要候选对象。

​​您可以在此处​​阅读有关 TCP 探测的更多信息。

配置初始探测延迟

可以通过多种方式配置探头。您可以指定它们应该运行的频率、成功和失败阈值是多少以及等待响应的时间。​​有关配置探针​​的文档非常清楚地说明了不同的选项及其作用。

但是,使用 liveness probe 时需要配置一项非常重要的设置。这是 initialDelaySeconds 设置。

结论

继续阅读