使用 Pod 故障策略处理可重试和不可重试的 Pod 故障

特性状态: Kubernetes v1.31 [稳定](默认启用)

本文档展示了如何使用 Pod 失败策略,结合默认的 Pod 回退失败策略,以提高对 Job 中容器或 Pod 级别失败的处理控制。

Pod 失败策略的定义可以帮助您

  • 通过避免不必要的 Pod 重试来更好地利用计算资源。
  • 避免由于 Pod 中断(例如 抢占API 发起的驱逐污点 导致的 Pod 中断)导致的 Job 失败。

开始之前

您应该已经熟悉 Job 的基本用法。

您需要一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场

您的 Kubernetes 服务器必须是 v1.25 或更高版本。

要检查版本,请输入 kubectl version

使用场景

考虑以下定义 Pod 失败策略的 Job 的使用场景

使用 Pod 失败策略避免不必要的 Pod 重试

通过以下示例,您可以学习如何使用 Pod 失败策略来避免在 Pod 失败指示不可重试的软件错误时进行不必要的 Pod 重启。

  1. 检查以下清单

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: job-pod-failure-policy-failjob
    spec:
      completions: 8
      parallelism: 2
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: main
            image: docker.io/library/bash:5
            command: ["bash"]
            args:
            - -c
            - echo "Hello world! I'm going to exit with 42 to simulate a software bug." && sleep 30 && exit 42
      backoffLimit: 6
      podFailurePolicy:
        rules:
        - action: FailJob
          onExitCodes:
            containerName: main
            operator: In
            values: [42]
    
  2. 应用清单

    kubectl create -f https://k8s.io/examples/controllers/job-pod-failure-policy-failjob.yaml
    
  3. 大约 30 秒后,整个 Job 应该终止。通过运行以下命令检查 Job 的状态

    kubectl get jobs -l job-name=job-pod-failure-policy-failjob -o yaml
    

    在 Job 状态中,显示以下条件

    • FailureTarget 条件:具有设置为 PodFailurePolicyreason 字段,以及包含有关终止的更多信息的 message 字段,例如 Container main for pod default/job-pod-failure-policy-failjob-8ckj8 failed with exit code 42 matching FailJob rule at index 0。Job 控制器在 Job 被认为失败后添加此条件。有关详细信息,请参阅 Job Pod 的终止
    • Failed 条件:与 FailureTarget 条件相同的 reasonmessage。Job 控制器在终止 Job 的所有 Pod 后添加此条件。

    作为比较,如果禁用了 Pod 失败策略,Job 将重试直到达到 backoffLimit(6 次失败)。由于重试使用指数退避,并且在 parallelism: 2 的情况下,失败成对发生,因此每次重试之间的延迟都会增加。因此,此示例将花费至少 9 分钟才能使 Job 失败。

清理

删除您创建的 Job

kubectl delete jobs/job-pod-failure-policy-failjob

集群会自动清理 Pod。

使用 Pod 失败策略忽略 Pod 中断

通过以下示例,您可以学习如何使用 Pod 失败策略来忽略来自增加 Pod 重试计数器到 .spec.backoffLimit 限制的 Pod 中断。

  1. 检查以下清单

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: job-pod-failure-policy-ignore
    spec:
      completions: 4
      parallelism: 2
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: main
            image: docker.io/library/bash:5
            command: ["bash"]
            args:
            - -c
            - echo "Hello world! I'm going to exit with 0 (success)." && sleep 90 && exit 0
      backoffLimit: 0
      podFailurePolicy:
        rules:
        - action: Ignore
          onPodConditions:
          - type: DisruptionTarget
    
  2. 应用清单

    kubectl create -f https://k8s.io/examples/controllers/job-pod-failure-policy-ignore.yaml
    
  3. 运行此命令以检查 Pod 被调度到的 nodeName

    nodeName=$(kubectl get pods -l job-name=job-pod-failure-policy-ignore -o jsonpath='{.items[0].spec.nodeName}')
    
  4. 排出节点以在 Pod 完成之前驱逐 Pod(在 90 秒内)

    kubectl drain nodes/$nodeName --ignore-daemonsets --grace-period=0
    
  5. 检查 .status.failed 以检查 Job 的计数器是否未增加

    kubectl get jobs -l job-name=job-pod-failure-policy-ignore -o yaml
    
  6. 取消清空节点

    kubectl uncordon nodes/$nodeName
    

Job 恢复并成功。

作为比较,如果禁用了 Pod 失败策略,Pod 中断将导致终止整个 Job(因为 .spec.backoffLimit 设置为 0)。

清理

删除您创建的 Job

kubectl delete jobs/job-pod-failure-policy-ignore

集群会自动清理 Pod。

使用 Pod 失败策略避免基于自定义 Pod 条件进行不必要的 Pod 重试

通过以下示例,您可以学习如何使用 Pod 失败策略来避免基于自定义 Pod 条件进行不必要的 Pod 重启。

  1. 检查以下清单

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: job-pod-failure-policy-config-issue
    spec:
      completions: 8
      parallelism: 2
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: main
            image: "non-existing-repo/non-existing-image:example"
      backoffLimit: 6
      podFailurePolicy:
        rules:
        - action: FailJob
          onPodConditions:
          - type: ConfigIssue
    
  2. 应用清单

    kubectl create -f https://k8s.io/examples/controllers/job-pod-failure-policy-config-issue.yaml
    

    请注意,该镜像配置错误,因为它不存在。

  3. 通过运行以下命令检查 Job 的 Pod 状态

    kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o yaml
    

    您将看到类似以下输出

    containerStatuses:
    - image: non-existing-repo/non-existing-image:example
       ...
       state:
       waiting:
          message: Back-off pulling image "non-existing-repo/non-existing-image:example"
          reason: ImagePullBackOff
          ...
    phase: Pending
    

    请注意,Pod 仍然处于 Pending 阶段,因为它无法拉取配置错误的镜像。原则上,这可能是一个瞬态问题,并且可以拉取镜像。但是,在这种情况下,镜像不存在,因此我们通过自定义条件指示这一事实。

  4. 添加自定义条件。首先通过运行以下命令准备补丁

    cat <<EOF > patch.yaml
    status:
      conditions:
      - type: ConfigIssue
        status: "True"
        reason: "NonExistingImage"
        lastTransitionTime: "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
    EOF
    

    其次,通过运行以下命令选择由 Job 创建的一个 Pod

    podName=$(kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o jsonpath='{.items[0].metadata.name}')
    

    然后,通过运行以下命令将补丁应用于其中一个 Pod

    kubectl patch pod $podName --subresource=status --patch-file=patch.yaml
    

    如果应用成功,您将收到类似以下通知

    pod/job-pod-failure-policy-config-issue-k6pvp patched
    
  5. 通过运行以下命令删除 Pod 以将其转换为 Failed 阶段

    kubectl delete pods/$podName
    
  6. 通过运行以下命令检查 Job 的状态

    kubectl get jobs -l job-name=job-pod-failure-policy-config-issue -o yaml
    

    在 Job 状态中,看到一个 Job Failed 条件,其 reason 字段等于 PodFailurePolicy。此外,message 字段包含有关 Job 终止的更详细信息,例如:Pod default/job-pod-failure-policy-config-issue-k6pvp has condition ConfigIssue matching FailJob rule at index 0

清理

删除您创建的 Job

kubectl delete jobs/job-pod-failure-policy-config-issue

集群会自动清理 Pod。

使用 Pod 失败策略避免每个索引不必要的 Pod 重试

为了避免每个索引不必要的 Pod 重启,您可以使用 Pod 失败策略每个索引的回退限制 功能。本页的这一部分展示了如何一起使用这些功能。

  1. 检查以下清单

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: job-backoff-limit-per-index-failindex
    spec:
      completions: 4
      parallelism: 2
      completionMode: Indexed
      backoffLimitPerIndex: 1
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: main
            image: docker.io/library/python:3
            command:
              # The script:
              # - fails the Pod with index 0 with exit code 1, which results in one retry;
              # - fails the Pod with index 1 with exit code 42 which results
              #   in failing the index without retry.
              # - succeeds Pods with any other index.
              - python3
              - -c
              - |
                import os, sys
                index = int(os.environ.get("JOB_COMPLETION_INDEX"))
                if index == 0:
                  sys.exit(1)
                elif index == 1:
                  sys.exit(42)
                else:
                  sys.exit(0)            
      backoffLimit: 6
      podFailurePolicy:
        rules:
        - action: FailIndex
          onExitCodes:
            containerName: main
            operator: In
            values: [42]
    
  2. 应用清单

    kubectl create -f https://k8s.io/examples/controllers/job-backoff-limit-per-index-failindex.yaml
    
  3. 大约 15 秒后,检查 Job 的 Pod 状态。您可以运行以下命令来执行此操作

    kubectl get pods -l job-name=job-backoff-limit-per-index-failindex -o yaml
    

    您将看到类似以下输出

    NAME                                            READY   STATUS      RESTARTS   AGE
    job-backoff-limit-per-index-failindex-0-4g4cm   0/1     Error       0          4s
    job-backoff-limit-per-index-failindex-0-fkdzq   0/1     Error       0          15s
    job-backoff-limit-per-index-failindex-1-2bgdj   0/1     Error       0          15s
    job-backoff-limit-per-index-failindex-2-vs6lt   0/1     Completed   0          11s
    job-backoff-limit-per-index-failindex-3-s7s47   0/1     Completed   0          6s
    

    请注意,输出显示以下内容

    • 由于允许一个索引的重试回退限制,因此有两个 Pod 具有索引 0。
    • 只有一个 Pod 具有索引 1,因为失败 Pod 的退出代码与具有 FailIndex 操作的 Pod 失败策略匹配。
  4. 通过运行以下命令检查 Job 的状态

    kubectl get jobs -l job-name=job-backoff-limit-per-index-failindex -o yaml
    

    在 Job 状态中,看到 failedIndexes 字段显示“0,1”,因为两个索引都失败了。由于未重试索引 1,因此指示的失败 Pod 数量,由状态字段“failed”等于 3。

清理

删除您创建的 Job

kubectl delete jobs/job-backoff-limit-per-index-failindex

集群会自动清理 Pod。

替代方案

您可以仅依赖 Pod 回退失败策略,通过指定 Job 的 .spec.backoffLimit 字段。但是,在许多情况下,很难找到一个平衡点,即设置 .spec.backoffLimit 的低值以避免不必要的 Pod 重试,同时又足够高以确保 Job 不会被 Pod 中断终止。

最后修改时间为太平洋标准时间 2026 年 2 月 12 日下午 4:20:修复 Pod 故障策略示例中的不正确的时间预估 (8bf021e511)