Kubernetes 1.28:改进了Job的故障处理

🤖 由 ChatGPT 生成的文章摘要

作者:Kevin Hannon(G-Research)、Michał Woźniak(Google)

本博客讨论 Kubernetes 1.28 中用于改进批量用户作业的两个新功能:Pod 替换策略和每个索引的退避限制。

这些功能延续了 Pod 故障策略所发起的努力,以改进作业中 Pod 故障的处理。

Pod replacement policy Pod 更换策略

默认情况下,当 Pod 进入终止状态(例如由于抢占或驱逐)时,Kubernetes 会立即创建一个替换 Pod。因此,两个 Pod 同时运行。用 API 术语来说,当 pod 具有 deletionTimestamp 且具有阶段 Pending 或 Running 时,它被视为终止。

对于一些流行的机器学习框架(例如 TensorFlow 和 JAX)来说,在给定时间运行两个 Pod 的情况是有问题的,对于给定索引,这些框架最多需要同时运行一个 Pod。如果两个 Pod 针对给定索引运行,Tensorflow 会给出以下错误。

 /job:worker/task:4: Duplicate task registration with task_name=/job:worker/replica:0/task:4

在前一个 Pod 完全终止之前创建替换 Pod 也可能会导致资源稀缺或预算紧张的集群出现问题,例如:

  • 对于待调度的 Pod 来说,很难获得集群资源,因为 Kubernetes 可能需要很长时间才能找到可用节点,直到现有 Pod 完全终止。
  • 如果启用集群自动缩放程序,替换 Pod 可能会产生不需要的扩展。

你可以如何使用它?

这是一项 alpha 功能,您可以通过在集群中打开JobPodReplacementPolicy功能门来启用该功能。

在集群中启用该功能后,您可以通过创建指定 podReplacementPolicy 字段的新作业来使用它,如下所示:

kind: Job
metadata:
 name: new
 ...
spec:
 podReplacementPolicy: Failed

在此作业中,Pod 仅在到达 Failed 阶段时才会被替换,而不是在它们终止时被替换。

此外,您还可以检查作业的.status.terminating字段。该字段的值是当前正在终止的 Job 拥有的 Pod 数量。

kubectl get jobs/myjob -o=jsonpath='{.items[*].status.terminating}'

3 # three Pods are terminating and have not yet reached the Failed phase

这对于外部队列控制器(例如 Kueue)特别有用,它跟踪作业的运行 Pod 的配额,直到从当前终止的作业回收资源。

请注意,使用自定义 Pod 失败策略时,podReplacementPolicy: Failed是默认值。

每个索引限制

默认情况下,索引作业的 Pod 失败计入全局重试限制,由.spec.backoffLimit表示。这意味着,如果存在持续失败的索引,则会重复重新启动,直到耗尽限制。一旦达到限制,整个作业将被标记为失败,并且某些索引可能永远不会启动。

对于您想要独立处理每个索引的 Pod 故障的用例来说,这是有问题的。例如,如果您使用索引作业来运行集成测试,其中每个索引对应一个测试套件。在这种情况下,您可能需要考虑可能的片状测试,允许每个套件重试 1 次或 2 次。可能存在一些有缺陷的套件,导致相应的索引始终失败。在这种情况下,您可能更愿意限制有问题的套件的重试,但允许其他套件完成。

该功能允许您:

  • 尽管某些索引失败,但仍完整执行所有索引。
  • 通过避免对持续失败的索引进行不必要的重试,更好地利用计算资源。

你可以如何使用它?

这是一项 alpha 功能,您可以通过打开集群中的 JobBackoffLimitPerIndex 功能门来启用该功能。

在集群中启用该功能后,您可以创建指定.spec.backoffLimitPerIndex字段的索引作业。

Example 例子

下面的示例演示了如何使用此功能来确保Job执行所有索引(前提是没有其他原因导致Job提前终止,例如达到 activeDeadlineSeconds 超时,或者被用户手动删除) ),并且每个索引都控制失败次数。

apiVersion: batch/v1
kind: Job
metadata:
 name: job-backoff-limit-per-index-execute-all
spec:
 completions: 8
 parallelism: 2
 completionMode: Indexed
 backoffLimitPerIndex: 1
 template:
 spec:
 restartPolicy: Never
 containers:
 - name: example # this example container returns an error, and fails,
 # when it is run as the second or third index in any Job
 # (even after a retry) 
 image: python
 command:
 - python3
 - -c
 - |
 import os, sys, time
 id = int(os.environ.get("JOB_COMPLETION_INDEX"))
 if id == 1 or id == 2:
 sys.exit(1)
 time.sleep(1)

现在,在作业完成后检查 Pod:

kubectl get pods -l job-name=job-backoff-limit-per-index-execute-all

返回与此类似的输出:

NAME READY STATUS RESTARTS AGE
job-backoff-limit-per-index-execute-all-0-b26vc 0/1 Completed 0 49s
job-backoff-limit-per-index-execute-all-1-6j5gd 0/1 Error 0 49s
job-backoff-limit-per-index-execute-all-1-6wd82 0/1 Error 0 37s
job-backoff-limit-per-index-execute-all-2-c66hg 0/1 Error 0 32s
job-backoff-limit-per-index-execute-all-2-nf982 0/1 Error 0 43s
job-backoff-limit-per-index-execute-all-3-cxmhf 0/1 Completed 0 33s
job-backoff-limit-per-index-execute-all-4-9q6kq 0/1 Completed 0 28s
job-backoff-limit-per-index-execute-all-5-z9hqf 0/1 Completed 0 28s
job-backoff-limit-per-index-execute-all-6-tbkr8 0/1 Completed 0 23s
job-backoff-limit-per-index-execute-all-7-hxjsq 0/1 Completed 0 22s

此外,您可以查看该作业的状态:

kubectl get jobs job-backoff-limit-per-index-fail-index -o yaml

输出以 status 结尾,类似于:

 status:
 completedIndexes: 0,3-7
 failedIndexes: 1,2
 succeeded: 6
 failed: 4
 conditions:
 - message: Job has failed indexes
 reason: FailedIndexes
 status: "True"
 type: Failed

这里,索引 1 和 2 都重试了一次。第二次失败后,每次都超出了指定的 .spec.backoffLimitPerIndex ,因此停止重试。为了进行比较,如果禁用了每个索引的退避,则有问题的索引将重试,直到超出全局 backoffLimit 为止,然后在启动一些较高的索引之前,整个作业将被标记为失败。

原文连接

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索