【9】pod健康检查(三种探针)

9.7 pod健康检查(三种探针)
  • pod健康检查和服务可用性检查:

    种类说明
    startupProbe启动探针k8s 1.16版本后引入的探测方式,用于判断容器内应用程序是否已经启动,如果配置了此探针,那么就会禁止其他的探测,直到它成功为止,成功后将不再探测。适用于某些应用启动比较慢的情况,如应用程序启动时需要与远程服务器建立网络连接,或者遇到网络访问较慢等情况,会造成容器启动缓慢,此时Readinessprob就不适用,因为这属于“有且仅有一次”的超长延时,可以通过StartupProbe
    LivenessProbe存活探针用于探测容器是否存活(Running状态),如果探测失败,kubelet 会“杀死”容器并根据重启策略进行相应处理,若没有配置该探针,那么默认就是success。
    ReadinessProbe就绪探针用于探测容器内的程序是否健康,如果它的值是success,那么代表这个容器已经完成或者启动,并且程序已经是可以接受流量的状态。
9.7.1 探针四种实现方式
实现方式说明
ExecAction在容器内部运行一个命令,如果该命令返回码为0,则表明容器健康。
TCPSocketAction通过容器的IP地址和端口号执行TCP检查,如果能够建立TCP连接,则表明容器健康。
HTTPGetAction通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应码在200-400之间,则认为容器健康。
gRPC

注:gRPC 容器探针功能进入 Beta 阶段,1.24 默认开启

9.7.2 配置探针

Probe 有很多配置字段,可以使用这些字段精确地控制启动、存活和就绪检测的行为:

1. initalDelaySeconds
  • 容器启动后要等待多少秒才启动 启动(startupProbe)、存活(livenessProbe)和就绪(readinessProbe)探针。
  • 如果定义了启动(starupProbe)探针,则存活(livenessProbe)探针和就绪(readinessProbe)探针的延迟将在启动(startupProbe)探针已成功之后才开始计算。
  • 如果 periodSeconds 的值大于 initialDelaySeconds,则 initialDelaySeconds 将被忽略。
  • 默认是 0 秒,最小值是 0。
2. periodSeconds
  • 执行探测的时间间隔(单位是秒)。
  • 默认是 10 秒。最小值是 1。
3. timeoutSeconds
  • 探测超时后等待多少秒。
  • 默认值是 1 秒。最小值是 1。
4. successThreshold
  • 探针在失败后,被视为成功的最小连续成功数。
  • 默认值是 1。最小值是1。
  • 存活(livenessProbe)和启动(startupProbe)探测的这个值必须是 1。
5. failureThreshold
  • 探针连续失败了 failureThreshold 次之后, Kubernetes 认为总体上检查已失败:容器状态未就绪、不健康、不活跃。
  • 对于启动(startupProbe)探针或存活(livenessProbe)探针而言,如果至少有 failureThreshold 个探针已失败, Kubernetes 会将容器视为不健康并为这个特定的容器触发重启操作。
  • kubelet 遵循该容器的 terminationGracePeriodSeconds 设置。
  • 对于失败的就绪(readinessProbe)探针,kubelet 继续运行检查失败的容器,并继续运行更多探针; 因为检查失败,kubelet 将 Pod 的 Ready 状况设置为 false
6. terminationGracePeriodSeconds
  • 为 kubelet 配置从为失败的容器触发终止操作到强制容器运行时停止该容器之前等待的宽限时长。
  • 默认值是继承 Pod 级别的 terminationGracePeriodSeconds 值。
  • 如果不设置则为 30 秒,最小值为 1。

注意:

如果就绪(readinessProbe)态探针的实现不正确,可能会导致容器中进程的数量不断上升。 如果不对其采取措施,很可能导致资源枯竭的状况。

9.7.3 livenessProbe 和 readinessProbe

场景:若是服务启动时间较长,虽然pod处于是Running状态,但是服务是不可用的

1. 创建探针
  1. 创建一个没有探针的 Pod
    此时会出现pod运行状态正常,但其实服务不可用。
apiVersion: v1 # 必选, API 的版本号
kind: Pod # 必选,类型 Pod
metadata: # 必选,元数据
  name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
spec: # 必选,用于定义 Pod 的详细信息
  containers: # 必选,容器列表
  - name: nginx # 必选,符合 RFC 1035 规范的容器名称
    image: nginx:latest # 必选,容器所用的镜像的地址
    imagePullPolicy: IfNotPresent
    command: # 可选,容器启动执行的命令
    - sh
    - -c
    - sleep 10; nginx -g "daemon off;"
    ports: # 可选,容器需要暴露的端口号列表
    - containerPort: 80 # 端口号
  restartPolicy: Never
#创建pod
[root@k8s-master tanzhen]# kubectl  create -f no-tanzhen.yaml 
pod/nginx created

#立即查看pod运行状态,此时已是Running
[root@k8s-master tanzhen]# kubectl  get pod -owide                    
NAME                            READY   STATUS             RESTARTS         AGE   IP              NODE         NOMINATED NODE   READINESS GATES
nginx                           1/1     Running            0                4s    172.28.82.206   k8s-master   <none>           <none>

#通过curl请求nginx,10秒之内,是拒绝服务的
[root@k8s-master tanzhen]# curl  172.28.82.206
curl: (7) Failed connect to 172.28.82.206:80; Connection refused

#通过curl请求nginx,10秒之后,nginx服务才能正常请求
[root@k8s-master tanzhen]# curl  172.28.82.206
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
......

配置readinessProbe和livenessProbe健康检查:

  apiVersion: v1 # 必选, API 的版本号
  kind: Pod # 必选,类型 Pod
  metadata: # 必选,元数据
    name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
  spec: # 必选,用于定义 Pod 的详细信息
    containers: # 必选,容器列表
    - name: nginx # 必选,符合 RFC 1035 规范的容器名称
      image: davralin/nginx-autoindex # 必选,容器所用的镜像带pkill命令的地址
      imagePullPolicy: IfNotPresent
      command: # 可选,容器启动执行的命令
      - sh
      - -c
      - sleep 10; nginx -g "daemon off;"
      readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。失败会切断流量
        httpGet: # 接口检测方式
          path: /index.html # 检查路径
          port: 80
          scheme: HTTP # HTTP or HTTPS
        #httpHeaders: # 可选, 检查的请求头
        #- name: end-user
        # value: Jason
        initialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间
        timeoutSeconds: 2 # 超时时间
        periodSeconds: 5 # 检测间隔,循环检测(时间可以长一些)
        successThreshold: 1 # 检查成功为 1 次表示就绪,接入流量
        failureThreshold: 2 # 检测失败 2 次表示未就绪,切断流量
      livenessProbe: # 可选,健康检查 存活检测,失败重启pod
        tcpSocket: # 端口检测方式
          port: 80
        initialDelaySeconds: 10 # 初始化时间
        timeoutSeconds: 2 # 超时时间
        periodSeconds: 5 # 检测间隔
        successThreshold: 1 # 检查成功为 1 次表示就绪
        failureThreshold: 2 # 检测失败 2 次表示未就绪
      ports: # 可选,容器需要暴露的端口号列表
      - containerPort: 80 # 端口号
    restartPolicy: Never
2.exec-liveness
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
       - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

在这个配置文件中,可以看到 Pod 中只有一个 ContainerperiodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /tmp/healthy 来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。

当容器启动时,执行如下命令:

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

这个容器生命的前 30 秒,/tmp/healthy 文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /tmp/healthy 会返回成功代码。 30 秒之后,执行命令 cat /tmp/healthy 就会返回失败代码。

在 30 秒内,查看 Pod 的事件,输出结果表明还没有存活探针失败::

# kubectl describe pod liveness-exec
Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  11s   default-scheduler  Successfully assigned default/liveness-exec to node01
  Normal  Pulling    9s    kubelet    Pulling image "busybox"
  Normal  Pulled     7s    kubelet    Successfully pulled image "busybox"
  Normal  Created    7s    kubelet    Created container liveness
  Normal  Started    7s    kubelet    Started container liveness

35 秒之后,再来看 Pod 的事件,在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了:

  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  57s                default-scheduler  Successfully assigned default/liveness-exec to node01
  Normal   Pulling    55s                kubelet    Pulling image "busybox"
  Normal   Pulled     53s                kubelet   Successfully pulled image "busybox"
  Normal   Created    53s                kubelet    Created container liveness
  Normal   Started    53s                kubelet    Started container liveness
  Warning  Unhealthy  10s (x3 over 20s)  kubelet    Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
  Normal   Killing    10s                kubelet    Container liveness failed liveness probe, will be restarted

再等 30 秒,确认这个容器被重启了:

# kubectl get pod liveness-exec

输出结果显示 RESTARTS 的值增加了 1。 请注意,一旦失败的容器恢复为运行状态,RESTARTS 计数器就会增加 1:

NAME            READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m
3. http-liveness
   apiVersion: v1
   kind: Pod
   metadata:
     labels:
       test: liveness
     name: liveness-http
   spec:
     containers:
     - name: liveness
       image: docker-ulucu-com.tencentcloudcr.com/base-service/liveness
       args:
       - /server
       livenessProbe:
         httpGet:
           path: /healthz
           port: 8080
           httpHeaders:
           - name: Custom-Header
             value: Awesome
         initialDelaySeconds: 3
         periodSeconds: 3

在这个配置文件中,你可以看到 Pod 也只有一个容器。 periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。 kubelet 会向容器内运行的服务(服务在监听 8080 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并将其重启。

返回大于或等于 200 并且小于 400 的任何代码都标示成功,其它返回代码都标示失败。

容器存活期间的最开始 10 秒中,/healthz 处理程序返回 200 的状态码。 之后处理程序返回 500 的状态码。

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    duration := time.Now().Sub(started)
    if duration.Seconds() > 10 {
        w.WriteHeader(500)
        w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
    } else {
        w.WriteHeader(200)
        w.Write([]byte("ok"))
    }
})

kubelet 在容器启动之后 3 秒开始执行健康检测。所以前几次健康检查都是成功的。 但是 10 秒之后,健康检查会失败,并且 kubelet 会杀死容器再重新启动容器。

10 秒之后,通过查看 Pod 事件来确认存活探针已经失败,并且容器被重新启动。

4. tcp-liveness-readinesss
apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: docker-ulucu-com.tencentcloudcr.com/base-service/goproxy:1.0
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

TCP 检测的配置和 HTTP 检测非常相似。

  • 就绪探针:kubelet 会在容器启动 5 秒后发送第一个就绪探针。 探针会尝试连接 goproxy 容器的 8080 端口。 如果探测成功,这个 Pod 会被标记为就绪状态,kubelet 将继续每隔 10 秒运行一次探测。
  • 存活探针: kubelet 会在容器启动 15 秒后进行第一次存活探测。 与就绪探针类似,存活探针会尝试连接 goproxy 容器的 8080 端口。 如果存活探测失败,容器会被重新启动。

15 秒之后,通过看 Pod 事件来检测存活探针:

# kubectl describe pod goproxy
5. grpc-liveness
apiVersion: v1
kind: Pod
metadata:
  name: etcd-with-grpc
spec:
  containers:
  - name: etcd
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.0-0
    command: [ "/usr/local/bin/etcd", "--data-dir",  "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
    ports:
    - containerPort: 2379
    livenessProbe:
      grpc:
        port: 2379
      initialDelaySeconds: 10

要使用 gRPC 探针,必须配置 port 属性。如果健康状态端点配置在非默认服务之上, 你还必须设置 service 属性。与 HTTP 和 TCP 探针不同,gRPC 探测不能使用命名端口或定制主机。

15 秒钟之后,查看 Pod 事件确认存活性检查并未失败:

# kubectl describe pod etcd-with-grpc
9.7.4 StartupProbe
  • 针对服务启动时间较长的场景。

  • 若通过增加存活(livenessProbe)探针的periodSeconds和failureThreshold配置,那么衍生出来,当服务启动之后,出现假死或者进程退出等情况下,pod不会在短时间内被重启,此时的服务是不可用的状态。

    apiVersion: v1 # 必选, API 的版本号
    kind: Pod # 必选,类型 Pod
    metadata: # 必选,元数据
      name: nginx # 必选,符合 RFC 1035 规范的 Pod 名称
    spec: # 必选,用于定义 Pod 的详细信息
      containers: # 必选,容器列表
      - name: nginx # 必选,符合 RFC 1035 规范的容器名称
        image: davralin/nginx-autoindex # 必选,容器所用的镜像的地址
        imagePullPolicy: IfNotPresent
        command: # 可选,容器启动执行的命令
        - sh
        - -c
        - sleep 30; nginx -g "daemon off;"
        startupProbe:
          tcpSocket: # 端口检测方式
             port: 80
          initialDelaySeconds: 10 # 初始化时间
          timeoutSeconds: 2 # 超时时间
          periodSeconds: 5 # 检测间隔
          successThreshold: 1 # 检查成功为 2 次表示就绪
          failureThreshold: 5 # 检测失败 1 次表示未就绪
        readinessProbe: # 可选,健康检查。注意三种检查方式同时只能使用一种。
          httpGet: # 接口检测方式
            path: /index.html # 检查路径
            port: 80
            scheme: HTTP # HTTP or HTTPS
            #httpHeaders: # 可选, 检查的请求头
            #- name: end-user
            # value: Jason
          initialDelaySeconds: 2# 初始化时间, 健康检查延迟执行时间
          timeoutSeconds: 2 # 超时时间
          periodSeconds: 5 # 检测间隔
          successThreshold: 1 # 检查成功为 2 次表示就绪
          failureThreshold: 2 # 检测失败 1 次表示未就绪
        livenessProbe: # 可选,健康检查
           httpGet:
              path: /index.html
              port: 80
              scheme: HTTP  
        #  exec: # 端口检测方式
          #  command:
           # - sh
           # - -c
            #- pgrep nginx
          initialDelaySeconds: 2 # 初始化时间
          timeoutSeconds: 2 # 超时时间
          periodSeconds: 5 # 检测间隔
          successThreshold: 1 # 检查成功为 2 次表示就绪
          failureThreshold: 2 # 检测失败 1 次表示未就绪
        ports: # 可选,容器需要暴露的端口号列表
        - containerPort: 80 # 端口号
      restartPolicy: Always
    
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值