K8S 三种探针 readinessProbe、livenessProbe和startupProbe


华为云开发者联盟

该内容已被华为云开发者联盟社区收录

加入社区


k8s

专栏收录该内容

44 篇文章17 订阅

订阅专栏

一、POD状态

Pod 常见的状态

Pending:挂起,我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件。已经创建了但是没有适合它运行的节点叫做挂起,这其中也包含集群为容器创建网络,或者下载镜像的过程。    


Running:Pod内所有的容器都已经被创建,且至少一个容器正在处于运行状态、正在启动状态或者重启状态。    


Succeeded:Pod中所以容器都执行成功后退出,并且没有处于重启的容器。


Failed:Pod中所以容器都已退出,但是至少还有一个容器退出时为失败状态。


Unknown:未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown



Pod重启策略

Always:      只要容器失效退出就重新启动容器。

OnFailure:  当容器以非正常(异常)退出后才自动重新启动容器。

Never:        无论容器状态如何,都不重新启动容器。


如果pod的restartpolicy没有设置,那么默认值是Always。

Pod常见状态转换场景



二、就绪、存活两种探针

K8S 提供了3种探针


readinessProbe

livenessProbe

startupProbe(这个1.16版本增加的)

探针介绍

在 Kubernetes 中 Pod 是最小的计算单元,而一个 Pod 又由多个容器组成,相当于每个容器就是一个应用,应用在运行期间,可能因为某也意外情况致使程序挂掉。那么如何监控这些容器状态稳定性,保证服务在运行期间不会发生问题,发生问题后进行重启等机制,就成为了重中之重的事情,考虑到这点 kubernetes 推出了活性探针机制。有了存活性探针能保证程序在运行中如果挂掉能够自动重启,但是还有个经常遇到的问题,比如说,在Kubernetes 中启动Pod,显示明明Pod已经启动成功,且能访问里面的端口,但是却返回错误信息。还有就是在执行滚动更新时候,总会出现一段时间,Pod对外提供网络访问,但是访问却发生404,这两个原因,都是因为Pod已经成功启动,但是 Pod 的的容器中应用程序还在启动中导致,考虑到这点Kubernetes推出了就绪性探针机制。


1、livenessProbe

livenessProbe:存活性探针,用于判断容器是不是健康,如果不满足健康条件,那么 Kubelet 将根据 Pod 中设置的 restartPolicy (重启策略)来判断,Pod 是否要进行重启操作。LivenessProbe按照配置去探测 ( 进程、或者端口、或者命令执行后是否成功等等),来判断容器是不是正常。如果探测不到,代表容器不健康(可以配置连续多少次失败才记为不健康),则 kubelet 会杀掉该容器,并根据容器的重启策略做相应的处理。如果未配置存活探针,则默认容器启动为通过(Success)状态。即探针返回的值永远是 Success。即Success后pod状态是RUNING


2、readinessProbe

readinessProbe 就绪性探针,用于判断容器内的程序是否存活(或者说是否健康),只有程序(服务)正常, 容器开始对外提供网络访问(启动完成并就绪)。容器启动后按照readinessProbe配置进行探测,无问题后结果为成功即状态为 Success。pod的READY状态为 true,从0/1变为1/1。如果失败继续为0/1,状态为 false。若未配置就绪探针,则默认状态容器启动后为Success。对于此pod、此pod关联的Service资源、EndPoint 的关系也将基于 Pod 的 Ready 状态进行设置,如果 Pod 运行过程中 Ready 状态变为 false,则系统自动从 Service资源 关联的 EndPoint 列表中去除此pod,届时service资源接收到GET请求后,kube-proxy将一定不会把流量引入此pod中,通过这种机制就能防止将流量转发到不可用的 Pod 上。如果 Pod 恢复为 Ready 状态。将再会被加回 Endpoint 列表。kube-proxy也将有概率通过负载机制会引入流量到此pod中。


3、就绪、存活两种探针的区别

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

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

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


4、就绪、存活两种探针的使用方法

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


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

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

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

探针探测结果有以下值:

Success:表示通过检测。

Failure:表示未通过检测。

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

LivenessProbe 和 ReadinessProbe 两种探针的相关属性


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

initialDelaySeconds:容器启动后要等待多少秒后就探针开始工作,单位“秒”,默认是 0 秒,最小值是 0

periodSeconds:执行探测的时间间隔(单位是秒),默认为 10s,单位“秒”,最小值是 1

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

successThreshold:探针检测失败后认为成功的最小连接成功次数,默认为 1s,在 Liveness 探针中必须为 1s,最小值为 1s。

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

注:initialDelaySeconds在readinessProbe其实可以不用配置,不配置默认pod刚启动,开始进行readinessProbe探测,但那有怎么样,除了

startupProbe,readinessProbe、livenessProbe运行在pod的整个生命周期,刚启动的时候readinessProbe检测失败了,只不过显示READY状

态一直是0/1,readinessProbe失败并不会导致重启pod,只有startupProbe、livenessProbe失败才会重启pod。而等到多少s后,真正服务启动

后,检查success成功后,READY状态自然正常

5、探针使用示例

5.1、LivenessProbe 探针使用示例

(1)、通过exec方式做健康探测


 [root@localhost ~]# vi 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:                #指令,类似于运行命令sh

       - cat                   #sh 后的第一个内容,直到需要输入空格,变成下一行

       - /tmp/healthy          #由于不能输入空格,需要另外声明,结果为sh 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 文件的内容,如果能成功执行这条命令一次(默认successThreshold:1),存活探针就认为探测成功,由于没有配置(failureThreshold、timeoutSeconds),所以执行(cat /tmp/healthy)并只等待1s,如果1s内执行后返回失败,探测失败。在前 30 秒内,由于文件存在,所以存活探针探测时执行 cat /tmp/healthy 命令成功执行。30 秒后 healthy 文件被删除,所以执行命令失败,Kubernetes 会根据 Pod 设置的重启策略来判断,是否重启 Pod。


(2)、通过HTTP方式做健康探测


 httpGet探测方式有如下可选的控制字段:


scheme: 用于连接host的协议,默认为HTTP。

host:要连接的主机名,默认为Pod IP,可以在http request head中设置host头部。

port:容器上要访问端口号或名称。

path:http服务器上的访问URI。

httpHeaders:自定义HTTP请求headers,HTTP允许重复headers。

 [root@localhost ~]# vi liveness-http.yaml   # 通过httpGet访问url


apiVersion: v1

kind: Pod

metadata:

 name: liveness-http

 labels:

   test: liveness

spec:

 containers:

 - name: liveness

   image: mydlqclub/springboot-helloworld:0.0.1

   livenessProbe:

     failureThreshold: 5       #检测失败5次表示未就绪

     initialDelaySeconds: 20   #延迟加载时间

     periodSeconds: 10          #重试时间间隔

     timeoutSeconds: 5         #超时时间设置

     successThreshold: 2       #检查成功为2次表示就绪

     httpGet:

       scheme: HTTP

       port: 8081

       path: /actuator/health

# 解释整体意思:

上面 Pod 中启动的容器是一个 SpringBoot 应用,其中引用了 Actuator 组件,提供了 /actuator/health 健康检查地址,在pod启动后,初始化等待20s后,livenessProbe开始工作,去请求HTTP://podIP:8081/actuator/health 接口,类似于curl -I HTTP://podIP:8081/actuator/health接口,考虑到请求会有延迟(curl -I后一直出现假死状态),所以给这次请求操作一直持续5s,如果5s内访问返回数值在>=200且<=400代表第一次检测success,如果是其他的数值,或者5s后还是假死状态,执行类似(ctrl+c)中断,并反回failure失败。等待10s后,再一次的去请求HTTP://podIP:8081/actuator/health接口。如果有连续的2次都是success,代表无问题。如果期间有连续的5次都是failure,代表有问题,直接重启pod,此操作会伴随pod的整个生命周期


通过自定义HTTP请求headers


   livenessProbe:

     failureThreshold: 5       #检测失败5次表示未就绪

     initialDelaySeconds: 20   #延迟加载时间

     periodSeconds: 10         #重试时间间隔

     timeoutSeconds: 5         #超时时间设置

     successThreshold: 2       #检查成功为2次表示就绪

     httpGet:

       port: 8080

       path: /health

       httpHeaders:

       - name: end-user

       - value: Jason

(3)、通过TCP方式做健康探测


 [root@localhost ~]# vi 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 端口,类似于telnet 80端口,如果连接失败则将杀死 Pod 重启容器。


5.2、ReadinessProbe 探针使用示例

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


[root@localhost ~]# vi 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


(2)、ReadinessProbe + LivenessProbe 配合使用示例

一般程序中需要设置两种探针结合使用,并且也要结合实际情况,来配置初始化检查时间和检测间隔,下面列一个简单的 SpringBoot 项目的 Deployment 例子。


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: apps/v1

kind: Deployment

metadata:

 name: springboot

 labels:

   app: springboot

spec:

 replicas: 1

 selector:

   matchLabels:

     app: springboot

 template:

   metadata:

     name: springboot

     labels:

       app: springboot

   spec:

     containers:

     - name: readiness

       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

         livenessProbe:

           initialDelaySeconds: 30

           periodSeconds: 10

           timeoutSeconds: 5

           httpGet:

             scheme: HTTP

             port: 8081

             path: /actuator/health

(3)、注意terminationGracePeriodSeconds不能用于就绪态探针(readinessProbe),如果将它应用于readinessProbe将会被APIserver接口所拒绝


----------------------------------

livenessProbe:

httpGet:

 path: /healthz

 port: liveness-port

failureThreshold: 1                

periodSeconds: 60                  

terminationGracePeriodSeconds: 60  # 宽限时间60s

----------------------------------

三、startupProbe探针

1、startupProbe探针介绍

k8s 在1.16版本后增加startupProbe探针,主要解决在复杂的程序中readinessProbe、livenessProbe探针无法更好的判断程序是否启动、是否存活。进而引入startupProbe探针为readinessProbe、livenessProbe探针服务。


2、startupProbe探针与另两种区别

如果三个探针同时存在,先执行startupProbe探针,其他两个探针将会被暂时禁用,直到pod满足startupProbe探针配置的条件,其他2个探针启动,如果不满足按照规则重启容器


另外两种探针在容器启动后,会按照配置,直到容器消亡才停止探测,而startupProbe探针只是在容器启动后按照配置满足一次后,不在进行后续的探测。


3、startupProbe探针方法、属性

startupProbe探针的使用方法跟 ReadinessProbe 和 livenessProbe 相同,对 Pod 的处置跟livenessProbe 方式相同,失败重启。


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

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

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

探针探测结果有以下值:

Success:表示通过检测。

Failure:表示未通过检测。

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

startupProbe探针属性跟 ReadinessProbe 和 livenessProbe 相同


initialDelaySeconds:容器启动后要等待多少秒后就探针开始工作,单位“秒”,默认是 0 秒,最小值是 0

periodSeconds:执行探测的时间间隔(单位是秒),默认为 10s,单位“秒”,最小值是 1

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

successThreshold:探针检测失败后认为成功的最小连接成功次数,默认为 1s,在 Liveness 探针中必须为 1s,最小值为 1s。

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

注:在startupProbe执行完之后,其他2种探针的所有配置才全部启动,相当于容器刚启动的时候,所以其他2种探针如果配置了initialDelaySeconds,建议不要给太长

4、为什么要使用startupProbe、使用场景

思考:startupProbe官方的解释(可以定义一个启动探针,该探针将推迟所有其他探针,直到 Pod 完成启动为止),startupProbe 启动探针存在的意义是不是: 如果服务A启动需要1分钟 ,我们存活探针探测的时候设置的是initialDelaySeconds 10s后开始探测,然后她探测的时候发现服务不正常,然后就开始重启Pod陷入死循环,但是如果意义在这个地方,那我们可以把探测时间调整大一点,failureThreshold 把这个也多设置几次就行了啊。 为什么还要单独的设置一个satrtupProbe呢


startupProbe的存在意义?


startupProbe 和 livenessProbe 最大的区别就是startupProbe在探测成功之后就不会继续探测了,而livenessProbe在pod的生命周期中一直在探测。


如果没有startupProbe探针的话我们只设置livenessProbe探针话会存在如下问题: 一个服务如果前期启动需要很长时间,那么它后面死亡未被发现的时间就越长,为什么会这么说呢?假设我们一个服务A启动完成需要2分钟,那么我们如下开始定义livenessProbe


livenessProbe:

 httpGet:

   path: /test

   prot: 80

failureThreshold: 1

initialDelay:5

periodSeconds: 5

如果我们这样定义的话,那pod 5s就会根据重启策略进行一次重启,这个时候你会发现pod一直会陷入死循环,那我们可以按照上面的猜想把配置改成这样


livenessProbe:

 httpGet:

   path: /test

   prot: 80

failureThreshold: 6

initialDelay:40

periodSeconds: 5

你肯定会说你看这样不就行了吗?这样的话pod就不会陷入死循环能启动起来了,确实这样pod能够启动起来了,但是你有没有考虑过这样一个问题,当我们启动完成之后,在后期的探测中,你需要6*5=30s才能发现这个pod不可用,这个时候你的服务已经停止运行了30s你才发现,这在生产中有可能是不会被原谅的。

还有就是这边只是我们假设一个服务A需要1分钟才能起来,但是在实际生产中你如何定义这些值呢???

针对上面这两个问题引入startupProbe之后都解决了


livenessProbe:

 httpGet:

   path: /test

   prot: 80

failureThreshold: 1

initialDelay:5

periodSeconds: 5

startupProbe:

 httpGet:

   path: /test

   prot: 80

failureThreshold: 60

initialDelay:5

periodSeconds: 5

我们这样设置之后,由于startupProbe探针的存在,程序有605s=300s的启动时间,一旦startupProbe探针探测成功之后,就会被livenessProbe接管,这样在运行中出问题livenessProbe就能在15=5s内发现。如果启动探测是3分钟内还没有探测成功,则接受Pod的重启策略进行重启。