Kubernetes

pod如何实现container的健康运行?

我们要解决的问题是什么?为什么要有livenessProbe? 它可以解决什么问题?

一 要解决的问题:container不响应请求

前面,我们知道通过在pod级别定义restartPolicy,可以实现pod自动重启container。进而解决了当container自身出现异常、故障时,pod会自动重启这些container。进而避免了由这些container提供的服务不可用的情况出现。

可是,这样就真的比较好的解决了问题吗?

试想:container自身并没有出现故障,而是出现了比如OutOfMemory的错误,或是程序故障陷入死循环导致,不能正常对外提供服务。那么此时,pod的restartPolicy就不生效了,不会去自动重启container了。

我们该怎么解决这个问题呢?于是,人们引入了一种解决方案:livenessProbe,存活探针。它是定义在每个container级别的,用来周期性的探测该container是不是正常的。它有指定的探测的策略和时间间隔,当它发现container不正常时,就会把container失败的结果”上报“给Kubernetes,然后Kubernetes就会根据pod上的restartPolicy来判断是不是要重启这个container。

二 livenessProbe的分类

  1. HTTP GET probe:向container的IP和端口,加上指定的路径上,发送一个HTTP请求,如果返回值是诸如2xx或者3xx的,则认为container是healthy,否则如果返回值是不符合预期的错误码、或者请求超时了,则认为container是故障的;
  2. TCP socket probe:向container的IP和指定的端口上,发起1个TCP socket连接请求。如果不能建立连接,或者连接超时,则认为container是故障的,否则连接正常的话,则container是OK的。
  3. Exec probe: 在container内部执行一个特定的命令,根据命令的返回结果来判断命令执行是否成功,进而判定container是否正常。

三 httpGet类型的livenessProbe验证

1 kiada pod yaml

[root@master-node Chapter06]# pwd
/root/kubernetes-in-action-2nd-edition/Chapter06
[root@master-node Chapter06]# cat pod.kiada-liveness.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: kiada-liveness
spec:
  containers:
  - name: kiada
    image: luksa/kiada:0.2
    ports:
    - name: http
      containerPort: 8080
    livenessProbe:
      httpGet:
        path: /
        port: 8080          #没有指定initialDelaySeconds、periodSeconds、timeoutSeconds、failureThreshold,其采用默认值,分别为10,10,1,3.
  - name: envoy
    image: luksa/kiada-ssl-proxy:0.1
    imagePullPolicy: Always
    ports:
    - name: https
      containerPort: 8443
    - name: admin
      containerPort: 9901
    livenessProbe:
      httpGet:
        path: /ready
        port: admin
      initialDelaySeconds: 10
      periodSeconds: 5
      timeoutSeconds: 2
      failureThreshold: 3
[root@master-node Chapter06]#     

2 创建pod

[root@master-node Chapter06]# kubectl apply -f pod.kiada-liveness.yaml 
pod/kiada-liveness created
[root@master-node Chapter06]# kubectl get pods -owide
NAME                       READY   STATUS      RESTARTS        AGE   IP             NODE     NOMINATED NODE   READINESS GATES
curl                       1/1     Running     14 (2d8h ago)   17d   10.244.2.245   node-2   <none>           <none>
curl-with-ambassador       2/2     Running     0               40d   10.244.1.47    node-1   <none>           <none>
downward                   1/1     Running     0               40d   10.244.1.45    node-1   <none>           <none>
fortune-configmap-volume   2/2     Running     0               48d   10.244.2.235   node-2   <none>           <none>
fortune-https              2/2     Running     0               47d   10.244.2.236   node-2   <none>           <none>
kiada-liveness             2/2     Running     0               7s    10.244.2.248   node-2   <none>           <none>
my-job-jfhz9               0/1     Completed   0               17d   10.244.2.244   node-2   <none>           <none>
[root@master-node Chapter06]# 

3 livenessProbe的字段含义

initialDelaySeconds: 表示,当container启动多久以后,开始执行livenessProbe探测;默认值是10秒; periodSeconds: 表示,每间隔多久重复执行livenessProbe探测;默认值是10秒; timeoutSeconds: 表示,在多久时间范围内,没收到container的响应请求,认为container失败1次;默认值是1秒; failureThreshold: 连续失败多少次,就认为container是彻底失败了,开始restart container;默认值是3次;

上述2个container分别设置了livenessProbe,其中第一个container kiada的livenessProbe没有显示指定相关字段,均采用默认值。表示,当container启动10秒以后,开始执行livenessProbe,如果在1秒内没有收到请求,记作container失败一次,间隔10秒之后,重复执行livenessProbe,如果联系3次都失败了,那么就开始重启这个container;

第二个container envoy显示指定了这几个字段,就按照指定的参数值来执行livenessProbe。

4 开启port-forward

[root@master-node ~]# kubectl port-forward --address=172.16.11.168 kiada-liveness 8080 8443 9901
Forwarding from 172.16.11.168:8080 -> 8080
Forwarding from 172.16.11.168:8443 -> 8443
Forwarding from 172.16.11.168:9901 -> 9901
Handling connection for 9901

5 监控events:kubectl get events -w

[root@master-node ~]# kubectl get events -w
LAST SEEN   TYPE      REASON                 OBJECT               MESSAGE
...
​

6 客户端向envoy container发起请求,模拟故障

$ curl -X POST 172.16.11.168:9901/healthcheck/fail
OK
​
asher at MacBook-Air-3 in ~
$ 
​

7 再次查看events

[root@master-node ~]# kubectl get events -w
LAST SEEN   TYPE      REASON                 OBJECT               MESSAGE
...
0s          Warning   EvictionThresholdMet   node/master-node     Attempting to reclaim ephemeral-storage
0s          Warning   Unhealthy              pod/kiada-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Warning   Unhealthy              pod/kiada-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Warning   Unhealthy              pod/kiada-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Normal    Killing                pod/kiada-liveness   Container envoy failed liveness probe, will be restarted
0s          Normal    Pulling                pod/kiada-liveness   Pulling image "luksa/kiada-ssl-proxy:0.1"
0s          Normal    Pulled                 pod/kiada-liveness   Successfully pulled image "luksa/kiada-ssl-proxy:0.1" in 2.760213466s
0s          Normal    Created                pod/kiada-liveness   Created container envoy
0s          Normal    Started                pod/kiada-liveness   Started container envoy

从上,我们可以看到,连续livenessProbe开始工作,并且探测到连续3次错误,Liveness probe failed: HTTP probe failed with statuscode: 503 出现3行之后。container被杀死,然后重启了。

验证了我们的livenessProbe符合我们的预期开始工作。

说明:当我们的客户端执行curl -X POST 172.16.11.168:9901/healthcheck/fail向container发起请求,模拟故障之后,在master上看到Liveness probe failed: HTTP probe failed with statuscode: 503。此时,我们再次向container发起请求,模拟container恢复正常之后,Kubernetes的livenessProbe不会再次认为container故障,并重启了。

发起正常请求的命令是:

$ curl -X POST 172.16.11.168:9901/healthcheck/ok
OK
​
asher at MacBook-Air-3 in ~
$ 

8 查看envoy这个container被重启的细节

kubectl describe pod kiada-liveness

[root@master-node Chapter06]# kubectl describe pod kiada-liveness 
Name:         kiada-liveness
Namespace:    default
Priority:     0
Node:         node-2/172.16.11.161
...
Containers:
  kiada:
...
 envoy:
    Container ID:   docker://5d8c136443f477606fc79114e020c75a9b2249612ac3376764cdcfec35246a61
    Image:          luksa/kiada-ssl-proxy:0.1
    Image ID:       docker-pullable://docker.io/luksa/kiada-ssl-proxy@sha256:ee9fc6cfe26a53c53433fdb7ce0d49c5e1bffb889adf4d7b8783ae9f273ecfe7
    Ports:          8443/TCP, 9901/TCP
    Host Ports:     0/TCP, 0/TCP
    State:          Running
      Started:      Fri, 27 May 2022 18:30:43 +0800
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Fri, 27 May 2022 18:25:39 +0800
      Finished:     Fri, 27 May 2022 18:30:40 +0800
    Ready:          True
    Restart Count:  1
    Liveness:       http-get http://:admin/ready delay=10s timeout=2s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-2mz9d (ro)

我们看到,envoy的信息:Last State: Terminated,Exit Code: 0,这里的退出代码是0,意味着,envoy是优雅的自动停止了。而不是被kill了,如果是kill的,则可以看到退出代码是137.

查看container被重启前的日志:kubectl logs kiada-liveness -c envoy -p

注意这里的-p表示的是previous,该container前一次的日志。

[root@master-node Chapter06]# kubectl logs  kiada-liveness -c envoy -p
...
[2022-05-27 10:30:40.441][1][warning][main] [source/server/server.cc:493] caught SIGTERM
[2022-05-27 10:30:40.441][1][info][main] [source/server/server.cc:613] shutting down server instance
[2022-05-27 10:30:40.441][1][info][main] [source/server/server.cc:560] main dispatch loop exited
[2022-05-27 10:30:40.442][1][info][main] [source/server/server.cc:606] exiting
[root@master-node Chapter06]#

意味着,container的进程被优雅的退出了。

9 envoy的livenessProbe工作流程图

四 tcpSocket类型的livenessProbe举例

如果container不支持HTTP请求的场景,可以使用tcpSocket类型的livenessProbe来验证container是否正常。

livenessProbe:
  tcpSocket:          #A
    port: 1234        #A
  periodSeconds: 2    #B
  failureThreshold: 1 #C
  
 #A This tcpSocket probe uses TCP port 1234
#B The probe runs every 2s
#C A single probe failure is enough to restart the container 

向container的1234端口发送tcp socket连接请求,如果在2s内不能建立连接,且失败1次,则认为container异常,需要restart。

五 exec类型的livenessProbe举例

对于HTTP get和tcp socket都不支持的container,可以通过exec类型来实现,探测container是否正常。

 livenessProbe:
   exec:
     command: #A
     - /usr/bin/healthcheck #A
   periodSeconds: 2 #B
   timeoutSeconds: 1 #C
   failureThreshold: 1 #D
#A The command to run and its arguments
#B The probe runs every second
#C The command must return within one second
#D A single probe failure is enough to restart the container

六 小结和参考

在pod上设置了restartPolicy来重启container的缺陷:当container表面看正常运行,但是当它陷入类似Java程序的内存溢出,或者OOM时,其实container是异常的,不能对外提供服务。而此时,pod是不会尝试重启container来解决问题。

我们可以通过给container加上livenessProbe来定期的探测container健康状况,从而确保container的正常运行。

对于生产环境的pod,我们都建议根据实际情况给container加上livenessProbe,来确保container的正常运行。

《Kubernetes in Action Second Edition》 Marko luksa

Chapter 06 managing the lifecycle of the Pod’s containers P152–P158.

一条评论

留言