Kubernetes 官方文档地址:

Pod 的整个生命阶段

  • Pending: 正在创建 Pod,但是 Pod 中的容器还没有全部被创建完成,这其中也包含集群为容器创建网络,或者下载镜像的过程
  • Running: Pod 内所有的容器都已经被创建,且至少一个容器正在处于运行状态、正在启动状态或者重启状态
  • Succeeded: Pod 中所有容器都执行成功后退出,并且没有处于重启的容器
  • Failed: Pod 中所有容器都已退出,但是至少还有一个容器退出时为失败状态
  • Unknown: 由于一些原因,Pod 的状态无法获取,通常是与 Pod 通信时出错导致的
    k8swd2.png

Pod 重启策略

  • Always: 只要容器失效退出就重新启动容器
  • OnFailure: 当容器以非正常退出后重新启动容器
  • Never: 无论容器状态如何,都不重新启动容器

如果 restartpolicy 没有设置,那么默认值是 Always,RC 和 DaemonSet 必须指定重启策略为 Always

Pod常见状态转换场景
k8swd3.png

应用部署到 Kubernetes 之后,要如何去保障应用的健康与稳定,可以从两个方面来进行增强:

  • 首先是提高应用的可观测性
  • 第二是提高应用的可恢复能力

从可观测性上来讲,可以在三个方面来去做增强:

  • 首先是应用的健康状态上面,可以实时地进行观测
  • 第二个是可以获取应用的资源使用情况
  • 第三个是可以拿到应用的实时日志,进行问题的诊断与分析

当出现了问题之后,首先要做的事情是要降低影响的范围,进行问题的调试与诊断。最后当出现问题的时候,理想的状况是:可以通过和 K8s 集成的自愈机制进行完整的恢复

三种探测方式

startupprobe、livenessProbe和ReadnessProbe

  • startupprobe: [启动检查],k8s1.16版本后新加的探测方式,用于判断容器内应用程序是否已经启动,如果配置了startuprobe,就会先禁用其他的探测,直到它成功为止,成功后将不再进行探测
  • livenessProbe:[活跃度探测],就是根据用户自定义的规则判断容器是否健康。也叫存活指针,如果 Liveness 指针判断容器不健康,此时会通过 kubelet 杀掉相应的 pod,并根据重启策略来判断是否重启这个容器。如果默认不配置 Liveness 指针,则默认情况下认为它这个探测默认返回是成功的
  • ReadnessProbe:[敏捷探测],用来判断这个容器是否启动完成,即 pod 的 状态(期望值)是否 为ready。如果探测的一个结果是不成功,那么此时它会从 pod 上 Endpoint 上移除,也就是说从接入层上面会把前一个 pod 进行摘除(设置pod为不可用的状态),直到下一次判断成功,这个 pod 才会再次挂到相应的 endpoint 之上

Endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址

startupprobe和Liveness应用场景
当我们在配置Liveness的时候,有时候会有一些特殊情况场景,你如设置容器启动10s检查一次,允许失败次数1,如果失败次数超过1则会触发restartPolicy,服务A启动时间很慢,需要60s。这个时候如果还是用上面的探针就会进入死循环,因为上面的探针10s后就开始探测,这时候我们服务并没有起来,发现探测失败就会触发restartPolicy,这时候可能会想到把initialDelay调成60s不就可以了?但是我们并不能保证这个服务每次起来都是60s,假如新的版本起来要70s,甚至更多的时间,我们就不好控制了,所以我们就可以将startupprobe和Liveness结合起来使用

Liveness和Readness两种探测机制的使用场景
Liveness 指针适用场景是支持那些可以重新拉起的应用,而 Readiness 指针主要应对的是启动之后无法立即对外提供服务的这些应用

Liveness和Readness两种探测机制的相同点和不同点
相同点是根据探测pod内某个应用或文件,来检查pod的健康状况,不同点是liveness如果探测失败会重启pod,而readliness则在连续3次探测失败之后,会将pod设置为不可用的状态,并不会重启pod

Liveness 指针和 Readiness 指针支持三种不同的探测方式

  • 第一种是 httpGet。它是通过发送 http Get 请求来进行判断的,当返回码是 200-399 之间的状态码时,标识这个应用是健康的
  • 第二种探测方式是 Exec。它是通过执行容器中的一个命令来判断当前的服务是否是正常的,当命令行的返回结果是 0,则标识容器是健康的
  • 第三种探测方式是 tcpSocket 。它是通过探测容器的 IP 和 Port 进行 TCP 健康检查,如果这个 TCP 的链接能够正常被建立,那么标识当前这个容器是健康的

第一种探测方式和第三种非常相似,一般常用的是第一和第二种的探测方式

探测机制实例测试

startupProbe

配置了 startupProbe 之后,livenessProbe和readinessProbe参数将会被暂时禁用,直到程序被检测到启动完成了livenessProbe,readinessProbe才会被启用
在程序启动较慢的时候可以配置startupProbe参数

[root@k8s01 probe]# vim startupProbe.yaml
...
startupProbe:                  #健康检查方式:[readinessProbe,livenessProbe,StartupProbe]
  failureThreshold: 3          #检测失败3次表示未就绪
  httpGet:                     #请求方式
    path: /ready               #请求路径
    port: 8081                #请求端口
    scheme: HTTP               #请求协议
  periodSeconds: 10            #检测间隔
  successThreshold: 1         #检查成功为1次表示就绪
  timeoutSeconds: 1           #检测失败1次表示未就绪
...

LivenessProbe

方法1:使用exec探测方式,查看pod内某个指定的文件是否存在,如果存在则认为状态为健康的,否则会根据设置的重启重启策略重启pod

[root@k8s01 probe]# vim livenss.yaml
kind: Pod
apiVersion: v1
metadata:
  name: liveness
  labels:
    name: liveness
spec:
  restartPolicy: OnFailure    ##定义重启策略,仅在pod对象出现错误时才重启
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300  #创建文件,并且在30秒后将文件进行删除
    livenessProbe:    #执行活跃度探测
      exec:
        command:
        - cat     #探测/tmp目录下是有test文件,如果有则代表健康,如果没有则执行重启pod策略
        - /tmp/test
      initialDelaySeconds: 10   #当容器运行多久之后开始探测(单位是s)
      periodSeconds: 5     #探测频率(单位s),每隔5秒探测一次

#运行该pod进行测试
[root@k8s01 probe]# kubectl  apply -f  livenss.yaml 
pod/liveness created      

探测机制中其他的可选字段:

  • initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒
  • periodSeconds:执行探测的频率,默认是10秒,最小1秒
  • timeoutSeconds:探测超时时间,默认1秒,最小1秒
  • successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功,默认是1,对于liveness必须是1,最小值是1
  • failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败,默认是3,最小值是1
    监测pod的状态,会在容器启动10秒后开始探测,且每5s探测一次
[root@k8s01 probe]#  kubectl get po
NAME                               READY   STATUS    RESTARTS   AGE
liveness                           1/1     Running   5          7m32s
nfs-provisioner-59cfc7646b-ns79z   1/1     Running   2          40d

我们可以看到pod一直在重启中,看到RESTARTS的次数已经为5次了,原因是在启动pod时执行了该命令:/bin/sh -c "touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300"
在容器生命的最初30秒内有一个 /tmp/test 文件,在这30秒内 cat /tmp/test命令会返回一个成功的返回码。但30秒后, cat /tmp/test 将返回失败的返回码,会触发pod的重启策略

[root@k8s01 probe]# kubectl  describe  pod liveness 

jcjz1.png
从上面的事件中可以发现,探测失败,将重启容器,原因是在指定的目录下没有发现该文件

方法2:使用httpGet探测方式,运行一个web服务,探测web网页的根目录下是否有指定的文件,也就等同于 “curl -I 容器ip地址:/healthy”(这里的目录/,指定的是容器内提供web服务的主目录

[root@k8s01 probe]# vim http-livenss.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    name: mynginx
spec:
  restartPolicy: OnFailure      #定义pod重启策略
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:       #定义探测机制
      httpGet:               #探测方式为httpGet
        scheme: HTTP    #指定协议
        path: /healthy       #指定路径下的文件,如果不存在,探测失败
        port: 80
      initialDelaySeconds: 10       #当容器运行多久之后开始探测(单位是s)
      periodSeconds: 5       #探测频率(单位s),每隔5秒探测一次
---
apiVersion: v1       #关联一个service对象
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    name: mynginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    
#运行该pod
[root@k8s01 probe]# kubectl  apply -f  http-livenss.yaml 
pod/web created
service/web-svc created    

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

  • host:连接的主机名,默认连接到pod的IP,你可能想在http header中设置”Host”而不是使用IP
  • scheme:连接使用的schema,默认HTTP
  • path: 访问的HTTP server的path
  • httpHeaders:自定义请求的header,HTTP运行重复的header
  • port:访问的容器的端口名字或者端口号,端口号必须介于1和65525之间
    查看pod运行10秒前的情况
    jcjz2.png
    最开始的10秒该容器是活着的,且返回的状态码为200
    jcjz3.png
    10秒后当探测机制开始探测时再次查看pod的情况
    jcjz4.png
[root@k8s01 probe]# kubectl describe pod web 

jcjz5.png
可以看到返回的状态码为404,表示在网页的根目录下并没有找到指定的文件,表示探测失败,且重启4次,状态是completed(完成的状态),说明pod是存在问题的

接下来我们继续进行检测,使其最终探测成功,修改pod的配置文件:

[root@k8s01 probe]# vim http-livenss.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    name: mynginx
spec:
  restartPolicy: OnFailure      #定义pod重启策略
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:       #定义探测机制
      httpGet:               #探测方式为httpGet
        scheme: HTTP    #指定协议
        path: /index.html       #指定路径下的文件,如果不存在,探测失败
        port: 80
      initialDelaySeconds: 10       #当容器运行多久之后开始探测(单位是s)
      periodSeconds: 5       #探测频率(单位s),每隔5秒探测一次
      
#重新运行pod:
[root@k8s01 probe]# kubectl  delete -f  http-livenss.yaml 
pod "web" deleted
service "web-svc" deleted
[root@k8s01 probe]# kubectl apply -f  http-livenss.yaml 
pod/web created
service/web-svc created      
#查看pod的状态及Events信息
[root@k8s01 probe]# kubectl get po -owide
NAME                               READY   STATUS    RESTARTS   AGE   IP             NODE                   NOMINATED NODE   READINESS GATES
nfs-provisioner-55f8f58fb7-bxxm4   1/1     Running   0          37d   10.244.2.44    k8s06.gazellio.local   <none>           <none>
web                                1/1     Running   0          71s   10.244.1.151   k8s04.gazellio.local   <none>           <none>

[root@k8s01 probe]# kubectl  describe  pod web 
Events:
  Type    Reason     Age    From                           Message
  ----    ------     ----   ----                           -------
  Normal  Scheduled  3m46s  default-scheduler              Successfully assigned default/web to k8s04.gazellio.local
  Normal  Pulling    3m45s  kubelet, k8s04.gazellio.local  Pulling image "nginx"
  Normal  Pulled     3m39s  kubelet, k8s04.gazellio.local  Successfully pulled image "nginx"
  Normal  Created    3m39s  kubelet, k8s04.gazellio.local  Created container nginx
  Normal  Started    3m39s  kubelet, k8s04.gazellio.local  Started container nginx
#测试访问网页头部信息:
[root@k8s01 probe]#  curl -I 10.244.1.11
HTTP/1.1 200 OK
Server: nginx/1.19.5
Date: Wed, 09 Dec 2020 07:49:14 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 24 Nov 2020 13:02:03 GMT
Connection: keep-alive
ETag: "5fbd044b-264"
Accept-Ranges: bytes

返回的状态码为200,表示这个pod的状况时健康的

ReadnessProbe探测

方法1:使用exec探测方式,与iveness相同,探测某个文件是否存在
pod的配置文件如下:

[root@k8s01 probe]# vim readiness.yaml
kind: Pod
apiVersion: v1
metadata:
  name: readiness
  labels:
    name: readiness
spec:
  restartPolicy: OnFailure
  containers:
  - name: readiness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/test; sleep 30; rm -rf /tmp/test; sleep 300;
    readinessProbe:   #定义readiness探测方式
      exec:
        command:
        - cat
        - /tmp/test
      initialDelaySeconds: 10
      periodSeconds: 5

#运行该pod
[root@k8s01 probe]# kubectl apply -f  readiness.yaml 
pod/readiness created            

检测pod的状态
jcjz6.png

#查看pod的Events:
[root@k8s01 probe]# kubectl  describe  pod readiness 

jcjz7.png
可以看到找不到该文件,表示探测失败,但是readiness机制与liveness机制不同,它并不会重启pod,而是连续探测3次失败后,则将容器设置为不可用的状态

方法2:httpGet方式

[root@k8s01 probe]# vim http-readiness.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web2
  labels:
    name: web2
spec:
  containers:
  - name: web2
    image: nginx
    ports:
    - containerPort: 81
    readinessProbe:
      httpGet:
        scheme: HTTP    #指定协议
        path: /healthy    #指定路径,如果不存在,则需要进行创建,否则探测失败
        port: 81
      initialDelaySeconds: 10
      periodSeconds: 5
---     
apiVersion: v1       
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    name: web2
  ports:
  - protocol: TCP
    port: 81             
    targetPort: 81
    
#运行该pod 
[root@k8s01 probe]# kubectl apply -f readiness.yaml
pod/readiness created   

查看pod的状态
jcjz8.png

jcjz9.png
查看pod的Events信息,通过探测,可以知道pod是不健康的,且http访问失败
它并不会重启,而是直接将pod设置为不可用的状态,endpoints会删除掉
jcjz10.png

检测时间计算

准确的时间计算:每次检查的间隔是10秒,最长超时时间是5秒,也就是单次检查应该是10 + 5 = 15秒(periodSeconds + timeoutSeconds),并不是10 * 5
所以最长的重启时间为(10 + 5)* 5
(periodSeconds + timeoutSeconds) * failureThreshold
此时又分为了两种情况:
1.首次启动时:最长重启时间需要加上initialDelaySeconds,因为需要等待initialDelaySeconds秒后才会执行健康检查。最长重启时间:(periodSeconds + timeoutSeconds) * failureThreshold + initialDelaySeconds
2.程序启动完成后:此时不需要计入initialDelaySeconds,最长重启时间:(periodSeconds + timeoutSeconds) * failureThreshold

文章作者: 鲜花的主人
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 爱吃可爱多
Kubernetes Kubernetes
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝