Kubernetes 对 Pod 的健康状态可以通过三类探针来检查:LivenessProbe、Readiness 及 StartupProbe,其中最主要的探针为 LivenessProbe 与 ReadinessProbe,kubelet 会定期执行这两类探针来诊断容器的健康状况。

LivenessProbe 存活探针

用于判断容器是否存活(Running 状态),如果 LivenessProbe 探针探测到容器不健康,则kubelet 将“杀掉”该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含 LivenessProbe 探针,那么 kubelet 认为该容器的 LivenessProbe 探针返回的值永远是 Success。
存活探针失败次数超过 failureThreshold 限制(默认三次),容器将被杀死,随后根据重启策略执行重启。
存活探针失败可能的原因:

  • 服务发生死锁,对所有请求均无响应
  • 服务线程全部卡在对外部 redis/mysql 等外部依赖的等待中,导致请求无响应

ReadinessProbe 就绪探针

用于判断容器服务是否可用(Ready 状态),达到 Ready 状态的 Pod 才可以接受请求。对于被 Service 管理的 Pod,Service 与 Pod Endpoint 的关联关系也将基于 Pod 是否 Ready 进行设置。

如果在运行过程中 Ready 状态变为 False(就绪探针失败次数超过 failureThreshold 默认三次限制),则系统自动将其从 Service 的后端 Endpoint 列表中隔离出去,后续再把恢复到 Ready 状态的 Pod 加回后端 Endpoint 列表。这样就能保证客户端在访问 Service 时不会被转发到服务不可用的 Pod 实例上。需要注意的是,ReadinessProbe 也是定期触发执行的,存在于 Pod 的整个生命周期中。

StartupProbe 启动探针

某些应用会遇到启动比较慢的情况,例如应用程序启动时需要与远程服务器建立网络连接,或者遇到网络访问较慢等情况时,会造成容器启动缓慢,此时 ReadinessProbe 就不适用了,因为属于 “有且仅有一次”的超长延时,可以通过 StartupProbe 探针解决该问题。在设置了StartupProbe 探针的情况下,LivenessProbe 探针和 ReadinessProbe 探针都将被禁用,直到 StartupProbe 探针返回成功为止。如果 StartupProbe 探针探测失败,kubelet 则将“杀掉”该容器,并根据容器的重启策略做相应的处理。此探针通过后,「就绪探针」与「存活探针」才会进行存活性与就绪检查。

用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉

  • startupProbe 显然比 livenessProbe 的 initialDelaySeconds 参数更灵活。
  • 同时它也能延迟 readinessProbe 的生效时间,这主要是为了避免无意义的探测。容器都还没 startUp,显然是不可能就绪的。

三种探针的应用场景

LivenessProbe 存活探针

容器应用在运行过程中由于存在 bug 或者主进程无法自行退出,kubelet 将借助 LivenessProbe 探针来判断容器进程是否处于不健康(或者僵死)状态,根据配置的条件判断容器处于不健康状态时,将对容器发起重启操作,以实现容器应用自动恢复。

如果希望 kublet 在探测失败时自动重启容器,则可以设置 Pod 的重启策略为 Always 或 OnFailure。

如果容器应用能够在遇到严重问题时自行崩溃退出,kubelet 则会根据 Pod 的重启策略重启该容器,无须设置 LivenessProbe 探针。

ReadinessProbe 就绪探针

对于提供服务类型的容器应用,若其处于 Ready 状态时才能接受请求时,则需要为容器应用配置 ReadinessProbe 探针。

容器在运行过程中,可能在某段时间无法提供服务(可能是由于性能问题),但是不希望 LivenessProbe 探测失败,这时可以设置一个与 LivenessProbe 不同的 ReadinessProbe 探针,以实现在无法提供服务时,将 Pod 从 Service 的后端列表中暂时移除,不再接受新的请求,等到服务恢复正常且可以接收请求之后,再恢复到 Ready 状态,继续接受新的请求。

在这个过程中可以允许 LivenessProbe 探针探测成功,容器不会被 kubelet 杀掉重启。

StartupProbe 启动探针

对于需要较长时间启动的容器,可以设置 StartupProbe 探针,支持暂时阻止 LivenessProbe 探针和 ReadinessProbe 探针的探测,等容器启动成功后,再启动后续的健康检查探测。

探针配置

探测器默认值

上述三类探测器的参数都是通用的,五个时间相关的参数列举如下:

  • initialDelaySeconds: 0 # 初始延迟时间,默认没有 delay 时间
  • periodSeconds: 10 # 周期时间10秒
  • timeoutSeconds: 1 # 超时时间1秒
  • failureThreshold: 3 # 失败阈值3次
  • successThreshold: 1 # 成功阈值1次

以上探针均可配置以下三种实现方式

ExecAction:

在容器内部运行一个命令,如果该命令的返回码为0,则表明容器健康。
下面例子,通过运行 cat /tmp/health 命令来判断一个容器运行是否正常。在该 Pod 运行后,将在创建 /tmp/health 文件 10s 后删除该文件,而 LivenessProbe 健康检查的初始探测时间 (initialDelaySeconds)为 15s,探测结果是 Fail,将导致 kubelet “杀掉”该容器并重启它:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/health
      initialDelaySeconds: 15
      timeoutSeconds: 1

TCPSocketAction:

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

下面例子,通过与容器内的 localhost:80 建立 TCP 连接进行健康检查:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-healthcheck
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1

HTTPGetAction:

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

下面例子,kubectl 定时发送 HTTP 请求到 localhost:80/_status/healthz 来进行容器应用的健康检查:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-healthcheck
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /_status/healthz
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1

示例1:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v3
spec:
  # ...
  template:
    #  ...
    spec:
      containers:
      - name: my-app-v3
        image: xxx.com/app/my-app:v3
        imagePullPolicy: IfNotPresent 
        # ... 省略若干配置
        startupProbe:
          httpGet:
            path: /actuator/health  # 直接使用健康检查接口即可
            port: 8080
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 20  # 最多提供给服务 5s * 20 的启动时间
          successThreshold: 1
        livenessProbe:
          httpGet:
            path: /actuator/health  # spring 的通用健康检查路径
            port: 8080
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 5
          successThreshold: 1
        # Readiness probes are very important for a RollingUpdate to work properly,
        readinessProbe:
          httpGet:
            path: /actuator/health  # 简单起见可直接使用 livenessProbe 相同的接口,当然也可额外定义
            port: 8080
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 5
          successThreshold: 1

示例2:
在 Kubernetes 1.18 之前,通用的手段是为「就绪探针」添加较长的 initialDelaySeconds 来实现类似「启动探针」的功能动,避免容器因为启动太慢,存活探针失败导致容器被重启。示例如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v3
spec:
  # ...
  template:
    #  ...
    spec:
      containers:
      - name: my-app-v3
        image: xxx.com/app/my-app:v3
        imagePullPolicy: IfNotPresent 
        # ... 省略若干配置
        livenessProbe:
          httpGet:
            path: /actuator/health  # spring 的通用健康检查路径
            port: 8080
          initialDelaySeconds: 120  # 前两分钟,都假设服务健康,避免 livenessProbe 失败导致服务重启
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 5
          successThreshold: 1
        # 容器一启动,Readiness probes 就会不断进行检测
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 3  # readiness probe 不需要设太长时间,使 Pod 尽快加入到 Endpoints.
          periodSeconds: 5
          timeoutSeconds: 1
          failureThreshold: 5
          successThreshold: 1