Kubernetes 中的活跃度探测可能很危险

笔记。 翻译。:Zalando 的首席工程师 Henning Jacobs 多次注意到 Kubernetes 用户在理解活性(和就绪)探针的目的及其正确使用方面存在问题。 因此,他将自己的想法集中在这篇大篇幅的笔记中,最终将成为 K8s 文档的一部分。

Kubernetes 中的活跃度探测可能很危险

健康检查,在 Kubernetes 中称为 活性探针 (即,字面意思是“生存能力测试”-大约翻译。),可能非常危险。 我建议尽可能避免使用它们:唯一的例外是当它们确实有必要并且您完全了解其使用的具体情况和后果时。 本出版物将讨论活性和就绪性检查,还将告诉您在什么情况下 成本 你不应该使用它们。

我的同事 Sandor 最近在 Twitter 上分享了他遇到的最常见错误,包括与使用就绪/活跃探针相关的错误:

Kubernetes 中的活跃度探测可能很危险

配置不正确 livenessProbe 可能会加剧高负载情况(滚雪球式关闭+可能较长的容器/应用程序启动时间)并导致其他负面后果,例如依赖性下降 (也可以看看 我最近的文章 关于限制K3s+ACME组合中的请求数量)。 当活性探针与健康检查(外部数据库)结合使用时,情况会更糟: 单个数据库故障将重新启动所有容器!

一般信息 “不要使用活性探针” 在这种情况下它没有多大帮助,所以让我们看看就绪性和活性检查的用途。

注意:下面的大部分测试最初包含在 Zalando 的内部开发人员文档中。

准备情况和活性检查

Kubernetes 提供了两种重要的机制,称为 活性探针和就绪探针。 它们定期执行某些操作(例如发送 HTTP 请求、打开 TCP 连接或在容器中执行命令)以确认应用程序是否按预期工作。

Kubernetes 使用 就绪探针了解容器何时准备好接受流量。 如果 Pod 的所有容器都准备就绪,则认为该 Pod 已准备好使用。 该机制的用途之一是控制将哪些 Pod 用作 Kubernetes 服务(尤其是 Ingress)的后端。

活性探针 帮助 Kubernetes 了解何时需要重新启动容器。 例如,这样的检查允许您在应用程序卡在一个地方时拦截死锁。 尽管出现错误,但在此状态下重新启动容器有助于应用程序启动,但也可能导致级联故障(见下文)。

如果您尝试部署未通过活动/就绪检查的应用程序更新,则其部署将因 Kubernetes 等待状态而停止 Ready 来自所有 pod。

例子

这是检查路径的就绪探针的示例 /health 通过 HTTP 使用默认设置 (间隔:10秒, 超时: 1秒, 成功门槛:1, 失败阈值:3):

# часть общего описания deployment'а/стека
podTemplate:
  spec:
    containers:
    - name: my-container
      # ...
      readinessProbe:
        httpGet:
          path: /health
          port: 8080

建议

  1. 对于具有 HTTP 端点(REST 等)的微服务 始终定义就绪探针,它检查应用程序 (pod) 是否准备好接受流量。
  2. 确保就绪探针 涵盖实际 Web 服务器端口的可用性:
    • 将端口用于管理目的,称为“admin”或“management”(例如,9090),例如 readinessProbe,确保端点仅在主 HTTP 端口(如 8080)准备好接受流量*时才返回 OK;

      *据我所知,Zalando 至少有一个案例没有发生这种情况,即 readinessProbe 我检查了“管理”端口,但由于加载缓存的问题,服务器本身没有开始工作。

    • 将就绪探针附加到单独的端口可能会导致主端口的过载不会反映在健康检查中(即服务器上的线程池已满,但健康检查仍然显示一切正常) )。
  3. 确保 就绪探针支持数据库初始化/迁移;
    • 实现此目的的最简单方法是仅在初始化完成后才联系 HTTP 服务器(例如,从 飞路 等等。); 也就是说,在数据库迁移完成之前不要启动 Web 服务器,而不是更改运行状况检查状态*。

      * 您还可以从 pod 外部的 init 容器运行数据库迁移。 我仍然喜欢独立应用程序,即应用程序容器知道如何在无需外部协调的情况下使数据库进入所需状态的应用程序。

  4. 使用 httpGet 通过典型的运行状况检查端点(例如, /health).
  5. 了解默认检查参数 (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • 默认选项意味着 pod 将变成 没有准备好 大约 30 秒后(3 次健全性检查失败)。
  6. 如果技术堆栈(例如 Java/Spring)允许,请使用单独的“admin”或“management”端口,将运行状况和指标管理与常规流量分开:
    • 但不要忘记第 2 点。
  7. 如有必要,就绪探针可用于预热/加载缓存并返回 503 状态代码,直到容器预热:

注意事项

  1. 不要依赖外部依赖 (例如数据仓库)运行就绪性/活跃性测试时 - 这可能会导致级联故障:
    • 举个例子,我们以一个有 10 个 Pod 的有状态 REST 服务为例,该服务依赖于一个 Postgres 数据库:当检查依赖于与数据库的工作连接时,如果网络/数据库端存在延迟,则所有 10 个 Pod 都可能会失败 - 通常是这样一切的结局都比它可能的更糟;
    • 请注意,Spring Data 默认检查数据库连接*;

      * 这是 Spring Data Redis 的默认行为(至少是我上次检查的时候),这导致了“灾难性”故障:当 Redis 短时间不可用时,所有 pod 都“崩溃”了。

    • 从这个意义上来说,“外部”也可以指同一应用程序的其他 pod,也就是说,理想情况下,检查不应依赖于同一集群的其他 pod 的状态,以防止级联崩溃:
      • 对于具有分布式状态的应用程序(例如,pod 中的内存缓存),结果可能会有所不同。
  2. 不要使用活性探针 对于 pod(例外情况是确实有必要并且您完全了解其使用的具体情况和后果):
    • 活性探针可以帮助恢复挂起的容器,但由于您可以完全控制应用程序,因此理想情况下不应发生挂起进程和死锁之类的情况:最好的替代方案是故意使应用程序崩溃并将其恢复到之前的稳定状态;
    • 失败的活性探测将导致容器重新启动,从而可能加剧加载相关错误的后果:重新启动容器将导致停机(至少在应用程序启动期间,例如 30 多秒),从而导致新的错误、增加其他集装箱的负载并增加其故障的可能性等;
    • 活性检查与外部依赖项相结合是最糟糕的组合,可能会导致级联故障:数据库端的轻微延迟将导致所有容器重新启动!
  3. 活性和就绪检查参数 一定是不同的:
    • 您可以使用具有相同运行状况检查但响应阈值更高的活性探针(failureThreshold),例如,分配状态 没有准备好 3次尝试后,并在10次尝试后认为活性探测失败;
  4. 不要使用执行检查,因为它们与导致僵尸进程出现的已知问题相关:

总结

  • 使用就绪探测来确定 Pod 何时准备好接收流量。
  • 仅在真正需要时才使用活性探针。
  • 就绪/活跃探针使用不当可能会导致可用性降低和级联故障。

Kubernetes 中的活跃度探测可能很危险

关于该主题的其他材料

1-2019-09 更新第 29 号

关于用于数据库迁移的 init 容器:添加了脚注。

EJ提醒我了 关于 PDB:活性检查的问题之一是 pod 之间缺乏协调。 库伯内特斯有 Pod 中断预算 (PDB) 限制应用程序可能遇到的并发故障数量,但是检查不考虑 PDB。 理想情况下,我们可以告诉 K8s“如果测试失败,则重新启动一个 Pod,但不要重新启动所有 Pod,以免事情变得更糟。”

布莱恩说得很完美:“当您确切知道什么时,请使用活性探测 最好的办法就是终止该应用程序“(再次强调,不要得意忘形)。

Kubernetes 中的活跃度探测可能很危险

2-2019-09 更新第 29 号

关于使用前阅读文档:我创建了相应的请求(功能要求)添加有关活性探针的文档。

译者PS

另请阅读我们的博客:

来源: habr.com

添加评论