05 Pod健康检查

现在在Pod的整个生命周期中,能影响到Pod的就只剩下健康检查这一部分了。在k8s集群当中,我们可以通过配置liveness probe(存活探针)readiness probe(可读性探针)来影响容器的生命周期。

  • kubelet通过liveness probe来确定你的应用程序是否正在运行,通俗点讲就是是否还活着。一般来说,如果你的程序一旦崩溃了,kubernetes就会立刻知道这个程序已经终止了,然后就会重启这个程序。而我们的liveness probe的目的就是来捕获到当前应用程序还没有终止,还没有崩溃,如果出现了这些情况,那么就重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去。

  • kubelet使用readiness probe来确定容器是否已经就绪就可以接收流量过来了。这个探针通俗点讲就是说是否准备好了,现在可以开始工作了。只有当Pod中的容器都处于就绪状态的时候kubelet才会认定该Pod处于就绪状态,因为一个Pod下面可能会有多个容器。当然Pod如果处于非就绪状态,那么我们就会将它从Service的Endpoints列表中移除出来,这样我们的流量就不会被路由到这个Pod里面来了。

和前面的钩子函数一样的,我们这两个探针支持下面的几种配置方式:

  • exec: 执行一段命令
  • http:检测某个http请求
  • tcpSocket:使用此配置,kubectl将尝试在指定端口上打开容器的套接字。如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。实际上就是检查端口。

我们先来给大家演示下存活探针的使用方法,首先我们用exec执行命令的方式来检测容器的存活,如下:(liveness-exec.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
spec:
  containers:
    - name: liveness
      image: busybox
      args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
      livenessProbe:
        exec:
          command:
            - cat
            - /tmp/healthy
        initialDelaySeconds: 5
        periodSeconds: 5

我们这里需要用到一个新的属性:livenessProbe,下面通过exec执行一段命令:

  • periodSeconds: 表示让kubelet每隔5s执行一次存活探针,也就是每5s执行一次上面的cat /tmp/healthy命令,如果命令执行成功了,将返回0,那么kubelet就会认为当前这个容器是存活的,如果返回的是非0值,那么kubelet就会把该容器杀掉然后重启它。periodSeconds的值默认是10s,最小1s。
  • initialDelaySeconds: 表示在第一次执行探针的时候要等待5s,这样能够确保我们的容器能够有足够的时间启动起来。大家可以想象一下,如果你的第一次执行探针等候的时间太短,是不是很有可能容器还没正常启动起来,所以存活探针很可能始终都是失败的,这样就会无休止的重启下去。

我们在容器启动的时候,执行了如下命令:
/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
意思是说在容器最开始的30s内创建一个/tmp/healthy文件,在这30s内执行cat /tmp/healthy命令都会返回一个成功的返回码。30s后,我们删除这个文件,现在执行cat /tmp/healthy是不是就会失败(默认检测失败3次才认为失败),所以这个时候就会重启容器了。

以下是过程

.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled    default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    2s         kubelet, node02    Pulling image "busybox"

##################################################################
.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled    default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    10s        kubelet, node02    Pulling image "busybox"
  Normal  Pulled     4s         kubelet, node02    Successfully pulled image "busybox"
  Normal  Created    4s         kubelet, node02    Created container liveness
  Normal  Started    4s         kubelet, node02    Started container liveness
##################################################################
.......
.......
.......
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled    default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal  Pulling    16s        kubelet, node02    Pulling image "busybox"
  Normal  Pulled     10s        kubelet, node02    Successfully pulled image "busybox"
  Normal  Created    10s        kubelet, node02    Created container liveness
  Normal  Started    10s        kubelet, node02    Started container liveness

##################################################################
.......
.......
.......
Volumes:
  default-token-557h9:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-557h9
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled            default-scheduler  Successfully assigned default/liveness-exec to node02
  Normal   Pulling    64s                kubelet, node02    Pulling image "busybox"
  Normal   Pulled     58s                kubelet, node02    Successfully pulled image "busybox"
  Normal   Created    58s                kubelet, node02    Created container liveness
  Normal   Started    58s                kubelet, node02    Started container liveness
  Warning  Unhealthy  14s (x3 over 24s)  kubelet, node02    Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    14s                kubelet, node02    Container liveness failed liveness probe, will be restarted

我们可以观察到容器是正常启动的,在隔一会,比如60s后,再查看下Pod的Event,在最下面有一条信息显示liveness probe失败了,容器将要重启。然后可以查看到Pod的RESTARTS值加1了:(我这里已经加到5了)

[root@node01 ~]# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
hook-demo1                      1/1     Running   0          25d
init-demo                       1/1     Running   0          25d
liveness-exec                   1/1     Running   5          7m20s
nginx-deploy-745bd74b44-4k2np   1/1     Running   0          26d
nginx-deploy-745bd74b44-jr7wv   1/1     Running   0          26d
nginx-deploy-745bd74b44-ngkrg   1/1     Running   0          26d
nginx-deploy-745bd74b44-plgkw   1/1     Running   0          26d

同样的,根据 periodSeconds 属性我们可以知道 kubelet 需要每隔3秒执行一次 liveness Probe,该探针将向容器中的 server 的 8080 端口发送一个 HTTP GET 请求。如果 server 的 /healthz 路径的 handler 返回一个成功的返回码,kubelet 就会认定该容器是活着的并且很健康,如果返回失败的返回码,kubelet 将杀掉该容器并重启它。initialDelaySeconds 指定kubelet 在该执行第一次探测之前需要等待3秒钟。

apiVersion: v1
kind: Pod
metada: 
  name: liveness-http
spec:
  containers:
    - name: liveness
      image: cnych/liveness
      args:
        - /server
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
          httpHeaders:
            - name: X-Custom-Header
              value: Awesome
        initialDelaySeconds: 3
        periodSeconds: 3

除了上面的 exec 和 httpGet 两种检测方式之外,还可以通过 tcpSocket 方式来检测端口是否正常,大家可以按照上面的方式结合kubectl explain命令自己来验证下这种方式。

另外前面我们提到了探针里面有一个initialDelaySeconds的属性,可以来配置第一次执行探针的等待时间,对于启动非常慢的应用这个参数非常有用,比如 Jenkins、Gitlab 这类应用,但是如何设置一个合适的初始延迟时间呢?这个就和应用具体的环境有关系了,所以这个值往往不是通用的,这样的话可能就会导致一个问题,我们的资源清单在别的环境下可能就会健康检查失败了,为解决这个问题,在 Kubernetes v1.16 版本官方特地新增了一个startupProbe(启动探针),该探针将推迟所有其他探针直到 Pod 完成启动为止,使用方法和存活探针一样:

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30  # 尽量设置大点
  periodSeconds: 10

比如上面这里的配置表示我们的慢速容器最多可以有5分钟(30个检查 * 10秒= 300s)来完成启动。

有的时候,应用程序可能暂时无法对外提供服务,例如,应用程序可能需要在启动期间加载大量数据或配置文件。在这种情况下,您不想杀死应用程序,也不想对外提供服务。那么这个时候我们就可以使用readiness probe来检测和减轻这些情况。 Pod 中的容器可以报告自己还没有准备,不能处理 Kubernetes 服务发送过来的流量。readiness probe的配置跟liveness probe基本上一致的。唯一的不同是使用readinessProbe而不是livenessProbe。两者如果同时使用的话就可以确保流量不会到达还未准备好的容器,准备好过后,如果应用程序出现了错误,则会重新启动容器。对于就绪探针我们会在后面 Service 的章节和大家继续介绍。

另外除了上面的initialDelaySeconds和periodSeconds属性外,探针还可以配置如下几个参数:

  • timeoutSeconds:探测超时时间,默认1秒,最小1秒。
  • successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是 1,但是如果是liveness则必须是 1。最小值是 1。
  • failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是 3,最小值是 1。

你可能感兴趣的:(05 Pod健康检查)