k8s:健康检查

健康检查

Pod中容器的生命周期的两个钩子函数,PostStart与PreStop,其中PostStart是在容器创建后立即执行的,而PreStop这个钩子函数则是在容器终止之前执行的。除了上面这两个钩子函数以外,还有一项配置会影响到容器的生命周期的,那就是健康检查的探针。
在Kubernetes集群当中,我们可以通过配置livenessprobe(存活探针)和readiness probe(就绪探针)来影响容器的生存周期。

* kubelet 通过使用 liveness probe 来确定你的应用程序是否正在运行,通俗点将就是是否还活着。一般来说,如果你的程序一旦崩溃了, Kubernetes 就会立刻知道这个程序已经终止了,然后就会重启这个程序。而我们的 livenessprobe 的目的就是来捕获到当前应用程序还没有终止,还没有崩溃,如果出现了这些情况,那么就重启处于该状态下的容器,使应用程序在存在 bug 的情况下依然能够继续运行下去。
* kubelet 使用 readiness probe 来确定容器是否已经就绪可以接收流量过来了。这个探针通俗点讲就是说是否准备好了,现在可以开始工作了。只有当 Pod 中的容器都处于就绪状态的时候 kubelet 才会认定该 Pod 处于就绪状态,因为一个 Pod 下面可能会有多个容器。当然 Pod 如果处于非就绪状态,那么我们就会将他从我们的工作队列(实际上就是 Service)中移除出来,这样我们的流量就不会被路由到这个 Pod 里面来了。

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

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

exec

先来给大家演示下存活探针的使用方法,首先我们用exec执行命令的方式来检测容器的存活。

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-exec
  labels:
    demo: lifecycle-exec
spec:
  containers:
  - name: lifecycle-exec
    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每隔5秒执行一次存活探针,也就是每5秒执行一次上面的cat /tmp/healthy命令,如果命令执行成功了,将返回0,那么kubelet就会认为当前这个容器是存活的并且很监控,如果返回的是非0值,那么kubelet就会把该容器杀掉然后重启它。另外一个属性initialDelaySeconds表示在第一次执行探针的时候要等待5秒,这样能够确保我们的容器能够有足够的时间启动起来。大家可以想象下,如果你的第一次执行探针等候的时间太短,是不是很有可能容器还没正常启动起来,所以存活探针很可能始终都是失败的,这样就会无休止的重启下去了。所以一个合理的initialDelaySeconds非常重要。

另外我们在容器启动的时候,执行了如下命令:

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"

意思是说在容器最开始的30秒内有一个/tmp/healthy文件,在这30秒内执行cat /tmp/healthy命令都会返回一个成功的返回码。30秒后,我们删除这个文件,现在执行cat/tmp/healthy是不是就会失败了,这个时候就会重启容器了。

我们来创建下该Pod,在30秒内,查看Pod的Event:

[root@master ~]# kubectl  describe pods lifecycle-exec
 Normal   Scheduled  >            default-scheduler  Successfully assigned default/lifecycle to node1
  Normal   Pulled     9m3s (x3 over 11m)   kubelet, node1     Successfully pulled image "busybox"
  Normal   Created    9m3s (x3 over 11m)   kubelet, node1     Created container lifecycle
  Normal   Started    9m3s (x3 over 11m)   kubelet, node1     Started container lifecycle

[root@master ~]# kubectl  exec lifecycle sh -- ls /tmp/healthy
/tmp/healthy

[root@master ~]# kubectl  get pods
NAME                                      READY   STATUS      RESTARTS   AGE
lifecycle                                 1/1     Running     1          3m15s
#重启次数 增加1 

我们可以观察到容器是正常启动的,在隔一会儿,比如40s后,再查看下Pod的Event,在最下面有一条信息显示liveness probe失败了,容器被删掉并重新创建。

[root@master ~]# kubectl  describe pods lifecycle-exec
Warning  Unhealthy  6m28s (x9 over 9m23s)  kubelet, node1     Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    6m28s (x3 over 9m13s)  kubelet, node1     Container lifecycle failed liveness probe, will be restarted
  Normal   Pulling    4m28s (x5 over 9m55s)  kubelet, node1     Pulling image "busybox"

然后通过kubectl get pod lifecycle-exec可以看到RESTARTS值加1了。

http

同样的,我们还可以使用HTTP GET请求来配置我们的存活探针

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-http
  labels:
    app: lifecycle-http
spec:
  containers:
  - name: lifecycle-http
    image: nginx
    ports:
    - containerPort: 80
      name: http
    readinessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 3
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 15
      periodSeconds: 20
      timeoutSeconds: 3
[root@master ~]# kubectl get pods 
NAME                                      READY   STATUS      RESTARTS   AGE
lifecycle-http                            1/1     Running     0          53s

[root@master ~]# kubectl  describe pods lifecycle-http
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  >  default-scheduler  Successfully assigned default/lifecycle-http to node1
  Normal  Pulling    92s        kubelet, node1     Pulling image "nginx"
  Normal  Pulled     76s        kubelet, node1     Successfully pulled image "nginx"
  Normal  Created    76s        kubelet, node1     Created container lifecycle-http
  Normal  Started    76s        kubelet, node1     Started container lifecycle-http

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

通常来说,任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码。

[root@master ~]# kubectl  exec  lifecycle-http sh -- rm -rf /usr/share/nginx/html/index.html

[root@master ~]# kubectl  describe pods lifecycle-http 
Warning  Unhealthy  3s         kubelet, node1     Liveness probe failed: HTTP probe failed with statuscode: 404
Warning  Unhealthy  1s         kubelet, node1     Readiness probe failed: HTTP probe failed with statuscode: 404

[root@master ~]# kubectl get pods
NAME                                      READY   STATUS      RESTARTS   AGE
lifecycle-http                            0/1     Running     1          4m43s 

Socket

然后我们来通过端口的方式来配置存活探针,使用此配置,kubelet将尝试在指定端口上打开容器的套接字。 如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-socket
  labels:
    app: lifecycle-socket
spec:
  containers:
  - name: lifecycle-socket
    image: nginx
    ports:
    - containerPort: 80
    readinessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 15
      periodSeconds: 20
[root@master ~]# kubectl  get pods 
NAME                                      READY   STATUS      RESTARTS   AGE
lifecycle-socket                          1/1     Running     0          59s

[root@master ~]# kubectl  get pods 
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  >  default-scheduler  Successfully assigned default/lifecycle-socket to node1
  Normal  Pulling    50s        kubelet, node1     Pulling image "nginx"
  Normal  Pulled     34s        kubelet, node1     Successfully pulled image "nginx"
  Normal  Created    34s        kubelet, node1     Created container lifecycle-socket
  Normal  Started    34s        kubelet, node1     Started container lifecycle-socket


我们可以看到,TCP 检查的配置与 HTTP 检查非常相似,只是将httpGet替换成了tcpSocket。 而且我们同时使用了readiness probe和liveness probe两种探针。 容器启动后5秒后,kubelet将发送第一个readiness probe(就绪探针)。 该探针会去连接容器的80端,如果连接成功,则该 Pod 将被标记为就绪状态。然后Kubelet将每隔10秒钟执行一次该检查。

除了readiness probe之外,该配置还包括livenessprobe。 容器启动15秒后,kubelet将运行第一个liveness probe。 就像readiness probe一样,这将尝试去连接到容器的8080端口。如果liveness probe失败,容器将重新启动。

有的时候,应用程序可能暂时无法对外提供服务,例如,应用程序可能需要在启动期间加载大量数据或配置文件。 在这种情况下,您不想杀死应用程序,也不想对外提供服务。 那么这个时候我们就可以使用readiness probe来检测和减轻这些情况。 Pod中的容器可以报告自己还没有准备,不能处理Kubernetes服务发送过来的流量。

从上面的YAML文件我们可以看出readiness probe的配置跟liveness probe很像,基本上一致的。唯一的不同是使用readinessProbe而不是livenessProbe。两者如果同时使用的话就可以确保流量不会到达还未准备好的容器,准备好过后,如果应用程序出现了错误,则会重新启动容器。

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

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

这就是liveness probe(存活探针)和readinessprobe(就绪探针)的使用方法。

你可能感兴趣的:(k8s,linux,centos,运维,k8s,容器)