使用 Pod 故障策略處理可重試和不可重試的 Pod 故障

特性狀態: Kubernetes v1.31 [stable] (預設啟用:true)

本文件向你展示瞭如何結合預設的 Pod 退避故障策略,使用 Pod 故障策略,以改進對 Job 中容器或 Pod 級別故障的處理控制。

Pod 故障策略的定義可以幫助你:

  • 透過避免不必要的 Pod 重試來更好地利用計算資源。
  • 避免因 Pod 中斷(例如搶佔API 發起的逐出或基於汙點的逐出)導致的 Job 故障。

準備工作

你應該已經熟悉 Job 的基本用法。

你需要有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用以下 Kubernetes 演練環境之一:

你的 Kubernetes 伺服器版本必須是 v1.25 或更高版本。

要檢查版本,請輸入 kubectl version

使用場景

考慮以下定義了 Pod 故障策略的 Job 使用場景:

使用 Pod 故障策略避免不必要的 Pod 重試

透過以下示例,你可以學習如何使用 Pod 故障策略來避免當 Pod 故障表示不可重試的軟體 bug 時,不必要的 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 狀況:其 reason 欄位設定為 PodFailurePolicy,並且 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 故障策略,Pod 將需要重試 6 次,至少需要 2 分鐘。

清理

刪除你建立的 Job

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

叢集會自動清理 Pod。

使用 Pod 故障策略忽略 Pod 中斷

透過以下示例,你可以學習如何使用 Pod 故障策略來忽略 Pod 中斷,避免其增加 Pod 重試計數器以達到 .spec.backoffLimit 限制。

  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 完成之前(90 秒內)驅逐 Pod:

    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 未重試,因此狀態欄位“failed”表示的失敗 Pod 數量等於 3。

清理

刪除你建立的 Job

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

叢集會自動清理 Pod。

替代方案

你可以完全依賴 Pod 退避故障策略,透過指定 Job 的 .spec.backoffLimit 欄位。然而,在許多情況下,在為 .spec.backoffLimit 設定一個低值以避免不必要的 Pod 重試,同時又足夠高以確保 Job 不會被 Pod 中斷終止之間找到平衡是很有問題的。

上次修改於 2025 年 3 月 27 日太平洋標準時間下午 2:06:文件更新,因為我們將 JobBackoffLimitPerIndex 提升到穩定版本 (#49811) (0d639b9629)