Kubernetes探针补充

2023年 7月 15日 35.6k 0

Kubernetes需要确保在 Pod 中运行的 应用是健康的。一旦应用出现问题,kubelet作为守护进程会根据为 Pod 设置的重启策略(restartPolicy)重启 Pod。现在的问题是 k8s 如何检测不健康的应用程序?答案是通过Probes。

  • restartPolicy默认为:Always

Liveness、Readiness 和 Startup 探针

Kubernetes有 3 种类型的 Probe:

  • Startup Probe:它是第一个探针(那么只要容器的启动探测没有成功,Kubernetes 就不会执行 liveness 或 readiness 探测。),用于确定应用程序是否已初始化。
  • Liveness Probe:用于检测应用程序是否崩溃/死锁。
  • Readiness Probe:此探针用于确定应用程序是否准备好处理请求

这些探针进一步利用不同的探针来获取容器内应用程序的运行状况:

  • tcpSocket:只需检查端口的 TCP 套接字是否成功
  • exec:运行一个返回 0 表示成功的命令
  • httpGet:HTTP 请求返回 200 到 399 之间的响应代码

可以进一步利用这些探针规范中的不同选项来控制 liveness 和 readiness 探针的行为:

  • initialDelaySeconds:容器启动后,在启动活动或就绪探测之前等待的秒数。默认为 0 秒。最小值为 0。
  • periodSeconds:执行探测的频率( 周期性重复)(以秒为单位)。默认为 10 秒。最小值为 1。
  • timeoutSeconds: 探测超时的秒数。默认为 1 秒。最小值为 1。
  • successThreshold:探测失败后被视为成功的最小连续成功次数。默认为 1。对于 liveness 和 startup Probes,必须为 1。最小值为 1。
  • failureThreshold:当一次探测失败时,Kubernetes 会尝试failureThreshold多次,然后放弃。在 liveness probe 的情况下放弃意味着重新启动容器。在就绪探测的情况下,Pod 将被标记为未就绪。默认为 3。最小值为 1。

以上是默认的一些配置,我们在什么时候使用什么方式?

常见场景

我们先举一些常见的场景,来突出监控检测的必要性

在k8s中,pod中的应用在没有启动完成就接收流量是不合理的。

  • 场景一:

1,当更新新的java程序版本的时候,java程序在启动前需要做一些初始化,如果没有配置Readiness,只要新的pod是runing状态,service的流量就会切入到新的pod中。如果此时java程序并没有完全初始化完成,那么连接此程序的服务就会感知到,进而受到更多影响。

2,除了java程序之外,我们还有一些其他的程序,受程序本身影响和其他外部因素影响。程序启动的时间并不固定

  • 场景二:

pod在运行的过程中,出现了异常,如果pod直接出现了错误的状态,那么按照restartPolicy的配置进行相应的动作。默认重启。

如果此时pod未出现状态错误,而是程序本身出现异常,且状态正常。那么就会出现pod runing,而业务已经无法正常使用。

基于以上场景,我们在看探针的方式。

image-20220125152822900.png

liveness

Kubectl 监视容器。如果容器进程崩溃,kubelet将根据重启策略处理它。但这并不总是有效的,进程可能不会崩溃,而是会陷入无限循环或死锁。重启策略可能不够细致。使用 liveness probe,你可以决定容器何时被认为是存活的。

Kubernetes 使用 liveness probe 来决定何时需要杀死容器以及何时启动另一个实例。由于Kubernetes 在 pod 级别运行,因此如果至少有一个容器报告为不健康,则相应的 pod 将被杀死

或者,我们可以反过来说:只有当一个 pod 的所有容器都报告为健康时,该 pod 才被认为是健康的。

  • 如果任何容器的活性探测失败,则 pod 的重启策略生效。确保重新启动策略不是从不,因为这会使探测无用。

    Kubernetes 中使用 liveness probe 执行健康检查的一些指南:

  • 应谨慎使用活性探针。如果一个程序启动本身检测手段的时间需要3秒,而你的检测是超时是1秒,这个时候将遇到多次随机崩溃和应用程序可用性低,或者不可用
  • 除非有充分的理由,否则不要使用活性探针。例如,一个很好的原因可能是应用程序中存在死锁的已知问题,而该问题的根本原因尚不清楚。
  • 执行简单快速的检查来确定进程的状态,而不是它的依赖关系。换句话说,你不想在 liveness 探测中检查外部依赖项的状态——这可能会由于大量容器重启和一小部分 Service Pod 过载而导致级联故障。
  • 如果你在容器中运行的进程在遇到不可恢复的错误时能够崩溃或退出,那么你可能根本不需要活性探测。
  • 使用保守的设置initialDelaySeconds来避免任何过早的容器重启并陷入重启循环。

exec 定义 liveness probe

使用一个简单的 Pod 创建一个 nginx 容器,并使用exec探针检查 nginx 服务状态。这意味着只要 nginx 服务处于 ' running' 状态,Pod 将被视为 alove,否则将根据其他配置选项(例如failureThreshold重试次数等)将其杀死。

以下是Pod 的 YAML 文件:

    livenessProbe:
      exec:
        command:
          - sh
          - -c
          - service nginx status | grep running
      initialDelaySeconds: 10
      periodSeconds: 5

首先,我们定义一个命令,Kubernetes 将作为容器内的探针执行。我们有一个 nginx 容器并使用 exec 探针来执行“ service nginx status”命令和字符串 ' running' 的 grep。默认情况下,nginx 服务应该处于运行状态。

其他两个设置initialDelaySecondsperiodSeconds,定义 Kubernetes 在启动容器后应该等待多长时间,直到它第一次执行探测,以及此后执行探测的频率。在我们的例子中,Kubernetes 在执行第一个探测之前等待 10 秒,然后每 5 秒执行一次探测。

httpGet 定义 liveness probe

使用httpGet来探测 pod 的活跃度。

通常对于带有 webservers 的容器,我们也可以直接使用 kubelet 向容器中运行并监听 端口的服务器发送 HTTP GET 请求。如果服务器路径的处理程序返回成功代码,则 kubelet 认为容器活着和健康。如果处理程序返回失败代码,kubelet 将杀死容器并重新启动它。

假定我们在程序中准备好了一个/HealthStatus路径,并且使用curl命令能够curl通

# curl 127.0.0.1:8010/HealthStatus

而后加到yaml中

          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /HealthStatus
              port: 8010
              scheme: HTTP
            initialDelaySeconds: 50
            periodSeconds: 20
            successThreshold: 1
            timeoutSeconds: 1
          ports:
            - containerPort: 8010
              protocol: TCP

tcpSocket 定义 liveness probe

Kubernetes 支持通过简单的 TCP 套接字检查进行健康检查。使用此配置,kubelet将尝试在指定端口上的容器打开一个套接字。如果它可以建立连接,则认为容器健康,如果不能,则认为容器失败。

以下是用于创建此 Pod 的 YAML 文件,tcpSocket作为活动健康检查的探针:

image-20220125151712356.png

          livenessProbe:
            failureThreshold: 1
            initialDelaySeconds: 50
            periodSeconds: 30
            successThreshold: 1
            tcpSocket:
              port: 9994
            timeoutSeconds: 1

readiness

Kubernetes 使用就绪探针来决定服务实例(即容器)何时准备好接受流量。未准备好的 Pod(仅当 Pod 的所有容器都已准备好时才准备好)将从 Service Endpoints 列表中删除,直到它们再次准备好。换句话说,它是一个信号,用于通知给定的 Pod 可用于传入 Service 的请求。

在 Kubernetes 中使用就绪探针执行健康检查时建议遵循的一些准则:

  • 每当容器可能无法在容器启动后立即正确地为流量提供服务时,请使用此探测。
  • 确保在就绪探测评估期间检查缓存预热或数据库迁移状态。如果尚未启动,可以考虑启动实际的预热过程,但请谨慎使用这种方法——准备就绪探测将在 Pod 的整个生命周期中不断执行,这意味着不应该为每个请求执行任何昂贵(耗费性能)的操作。或者,你可能希望为此目的使用启动探针,这是 Kubernetes 1.16 中新引入的。
  • 对于公开 HTTP 端点的微服务应用程序,请考虑始终配置 httpGet 就绪探针。这将确保在容器成功运行但 HTTP 服务器未完全初始化时涵盖所有情况。
  • 在应用程序中使用单独的专用 HTTP 端点进行就绪检查是一个好主意,例如,一个常见的约定是使用/health.
  • 如果在这种类型的探测中检查依赖项(外部数据库和日志服务)的状态,请小心共享依赖项,例如投票应用程序中的 SQL Server。在这种情况下,应该考虑使用探测超时,该超时大于外部依赖项允许的最大超时 - 否则,可能会遇到级联故障并降低可用性,而不是偶尔增加延迟。

httpget 定义就绪探测

httpGet

          livenessProbe:
            failureThreshold: 1
            initialDelaySeconds: 50
            periodSeconds: 30
            successThreshold: 1
            tcpSocket:
              port: 9994
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 3
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 9994
            timeoutSeconds: 1

以上配置说明,就绪在容器启动后30秒开始执行,并且30秒执行一次就绪检测

基于host

          readinessProbe:
              initialDelaySeconds: 1
            periodSeconds: 2
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 1
            httpGet:
                host:
              scheme: HTTP
              path: /
              httpHeaders:
              - name: Host
              value: linuxea.com
              port: 8080

httpget健康和就绪实践

  • 活性探针

    initialDelaySeconds :应该比应用程序启动时间更长,这样容器就不会陷入重启循环

  • 就绪探针

    initialDelaySeconds : 比进程启动成功的实践长即可,因为我们希望在容器准备好后立即启用到 pod 的流量

image-20220125151556164.png

          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /HealthStatus
              port: 8010
              scheme: HTTP
            initialDelaySeconds: 50
            periodSeconds: 20
            successThreshold: 1
            timeoutSeconds: 1
          ports:
            - containerPort: 8010
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /HealthStatus
              port: 8010
              scheme: HTTP
            initialDelaySeconds: 30
            periodSeconds: 30
            successThreshold: 1
            timeoutSeconds: 1

健康状态在容器启动后50秒开始执行,每隔20秒执行一次,超时1秒,失败最多三次

就绪状态在容器启动后30秒开始执行,每隔30秒执行一次,超时1秒,失败最多三次

当失败三次后根据restartPolicy的配置执行相应的动作

Startup Probe

如果你认为就绪和健康探针已经解决了问题,实际上并没有,我们还需要Startup Probe来解决日益严重的超时问题,我们希望有一个配置能够概况了就绪和健康探针的时间,我们不想再过多的关注到超时时长上,这将导致pod进入流量过慢。

当容器变得无响应时,liveness probe 将重新启动容器,并且 readiness probe 用于决定容器何时准备好启动或停止接受流量。许多人认为就绪探测仅在启动时调用,但即使在容器被启动为就绪后它仍会继续调用。例如,如果一个容器暂时繁忙,它可能会变得未就绪,以便将请求路由到其他 pod。如果准备就绪探测评估一组 pod 之间的共享依赖关系,那么如果配置过于激进,就有可能导致整个服务不可用。但是,没有办法在启动时进行积极的就绪探测——使容器尽快可用于请求——在稳态操作期间使用不那么积极的就绪探测。

许多应用程序的启动动态与稳态显着不同。应用程序初始化所特有的动态包括: 填充缓存;在事件源应用程序中从日志中重新实现派生状态;或建立与依赖项(如数据库)的持久连接。这使得调整 liveness 和 readiness 探针具有挑战性。例如,如果initialDelaySeconds对于一个 liveness 探测不够保守,一个容器可能在它启动之前就被杀死了。如果启动动态随时间发生变化,这尤其具有挑战性,可能随着你的系统扩展或工作负载的场景变化。如果容器有一段时间没有重新启动并且启动时间增加了,那么在将配置修改为增加之前,你可能无法重新启动 Pod initialDelaySeconds

这个时候就用到了Startup Probe,Kubernetes 运行的第一个探针是Startup Probe,为什么说是第一,因为一旦Startup Probe失败,将结束。只有Startup Probe成功才会健康探针和就绪探针的操作。

相信你已经很清楚了。启动探针旨在解决这些问题。启动探针仅在启动期间调用,用于确定容器何时准备好接受请求。如果配置了启动探测,则会禁用活动性和就绪性检查,直到启动探测成功。如果启动探测超出了配置failureThreshold但没有成功,容器将被杀死并重新启动,这取决于 pod 的restartPolicy,类似于 liveness 探测的行为。

此探测有助于确定应用程序是否已初始化。通常,初始化应用程序可能只需要几毫秒的时间,但一些足够大的应用程序可能需要几秒钟(或更多)来初始化。所以Startup Probe主要用于初始化时间较长的大型应用程序

描述的适用于启动探针:

  • 设置timeoutSecondsfailureThreshold保守配置,以便系统动态可以临时或永久更改,而不会导致启动探测失败,从而阻止容器启动。
  • 如果启动探针调用的路由直接检查依赖关系或执行昂贵的操作,请考虑设置timeoutSeconds相同的量级,以避免积累资源或重载依赖关系。即使启动探测超时,服务可能仍在执行请求。
  • 定期重启容器以清理启动动态并避免随着时间的推移出现意外的行为变化。如果一个 pod 运行了几个月或几年而没有重新启动,那就需要担心了

启动探针也有一些独特的考虑:

  • 要使启动缓慢的容器尽快可用,请使用具有非常短的超时但也非常长的故障阈值的启动探针,以避免在容器启动之前将其杀死。
  • 就绪和活跃度探测独立于启动探测这一事实允许对启动探测失败非常保守,或者执行不同的检查,也许检查仅在启动时相关,或者过于昂贵而无法通过定期执行准备就绪或活跃度探测。

启动探针视为仅在启动时运行的活跃度和就绪度探针的组合。使用启动探针将活动性和就绪性检查与应用程序初始化分离,最终使服务更加可靠

需要注意:

  • 当应用程序处于初始化阶段时,启动探测器会返回一些 http 错误代码,从 400 到 599。
  • 一旦应用程序被初始化,启动探测将返回一个从 200 到 299 的 http 成功代码。这意味着探测成功,现在启动探测将不会在该容器的生命周期内再次运行。
  • 可以指示 kubernetes 应该为此探测执行多少次尝试。所有这些尝试的启动探测都失败了,然后 kubernetes 最终会杀死容器,并重新启动 pod。

Startup Probe在部署 yaml 文件中定义

          startupProbe:
            httpGet:
              path: /health
              port: 80
            failureThreshold: 25
            periodSeconds: 10

Startup 探针在startupProbe字段中定义,并在端口 80 上调用 URL /health

failureThreshold指定应尝试探测的次数。给它的值是 25。periodSeconds字段指定检查之间的等待时间。

这意味着 Startup Probe 将持续 25*10=250 秒,当它通过时 k8s 启动 liveness 和 readiness 探针。

如果在这 250 秒内都失败了,那么 k8s 将杀死该 pod 并重新启动另一个

参考

linuxea:kubernetes 存活状态liveness probe(7)

linuxea:kubernetes 就绪检测readiness probe(8)

Kubernetes Liveness vs Readiness Probe

相关文章

LeaferJS 1.0 重磅发布:强悍的前端 Canvas 渲染引擎
10分钟搞定支持通配符的永久有效免费HTTPS证书
300 多个 Microsoft Excel 快捷方式
一步步配置基于kubeadmin的kubevip高可用
istio全链路传递cookie和header灰度
REST Web 服务版本控制

发布评论