使用 Pod 失敗策略處理可重試與不可重試的 Pod 失敗

功能狀態: Kubernetes v1.31 [穩定] (預設啟用:true)

本文件向您展示如何使用 Pod 失敗策略,結合預設的 Pod 退避失敗策略,以改善對 Job 內容器或 Pod 層級失敗處理的控制。

Pod 失敗策略的定義可以幫助您

開始之前

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

您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且不充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用以下 Kubernetes playground 之一

您的 Kubernetes 伺服器必須是 v1.25 或更新版本。若要檢查版本,請輸入 kubectl version

使用 Pod 失敗策略避免不必要的 Pod 重試

透過以下範例,您可以學習如何在 Pod 失敗指示不可重試的軟體錯誤時,使用 Pod 失敗策略來避免不必要的 Pod 重新啟動。

首先,根據組態建立 Job

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]

透過執行

kubectl create -f job-pod-failure-policy-failjob.yaml

大約 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 失敗原則,Pod 將會重試 6 次,至少需要 2 分鐘。

清理

刪除您建立的 Job

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

叢集會自動清理 Pod。

使用 Pod 失敗原則來忽略 Pod 中斷

透過以下範例,您可以學習如何使用 Pod 失敗原則來忽略 Pod 中斷,避免 Pod 重試計數器朝 .spec.backoffLimit 限制遞增。

  1. 根據設定檔建立 Job

    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
    

    透過執行

    kubectl create -f job-pod-failure-policy-ignore.yaml
    
  2. 執行此命令以檢查 Pod 排程到的 nodeName

    nodeName=$(kubectl get pods -l job-name=job-pod-failure-policy-ignore -o jsonpath='{.items[0].spec.nodeName}')
    
  3. 排空節點以在 Pod 完成前 (90 秒內) 驅逐 Pod

    kubectl drain nodes/$nodeName --ignore-daemonsets --grace-period=0
    
  4. 檢查 .status.failed 以確認 Job 的計數器未遞增

    kubectl get jobs -l job-name=job-pod-failure-policy-ignore -o yaml
    
  5. 解除節點封鎖

    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. 首先,根據組態建立 Job

    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
    

    透過執行

    kubectl create -f job-pod-failure-policy-config-issue.yaml
    

    請注意,此映像檔設定錯誤,因為它不存在。

  2. 執行以下命令來檢查 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 階段,因為它無法提取設定錯誤的映像檔。原則上,這可能是一個暫時性問題,映像檔可能會被提取。但是,在本例中,映像檔不存在,因此我們透過自訂狀況來指出此事實。

  3. 新增自訂狀況。首先,執行以下命令準備修補程式

    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
    
  4. 執行以下命令刪除 Pod,使其轉換為 Failed 階段

    kubectl delete pods/$podName
    
  5. 執行以下命令檢查 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 退避失敗原則,透過指定 Job 的 .spec.backoffLimit 欄位。但是,在許多情況下,要在設定較低的 .spec.backoffLimit 值以避免不必要的 Pod 重試,以及設定足夠高的值以確保 Job 不會因 Pod 中斷而終止之間找到平衡點,是很有問題的。

上次修改時間為太平洋標準時間 2024 年 7 月 29 日下午 8:56:將 Job Pod 失敗原則升級為穩定版本 (#46807) (45a47d170f)