使用 Pod 故障策略處理可重試和不可重試的 Pod 故障
Kubernetes v1.31 [stable]
(預設啟用:true)本文件向你展示瞭如何結合預設的 Pod 退避故障策略,使用 Pod 故障策略,以改進對 Job 中容器或 Pod 級別故障的處理控制。
Pod 故障策略的定義可以幫助你:
準備工作
你應該已經熟悉 Job 的基本用法。
你需要有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用以下 Kubernetes 演練環境之一:
你的 Kubernetes 伺服器版本必須是 v1.25 或更高版本。要檢查版本,請輸入 kubectl version
。
使用場景
考慮以下定義了 Pod 故障策略的 Job 使用場景:
使用 Pod 故障策略避免不必要的 Pod 重試
透過以下示例,你可以學習如何使用 Pod 故障策略來避免當 Pod 故障表示不可重試的軟體 bug 時,不必要的 Pod 重啟。
檢查以下清單:
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 https://k8s.io/examples/controllers/job-pod-failure-policy-failjob.yaml
大約 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
狀況具有相同的reason
和message
。Job 控制器在所有 Job 的 Pod 終止後新增此狀況。
相比之下,如果停用了 Pod 故障策略,Pod 將需要重試 6 次,至少需要 2 分鐘。
清理
刪除你建立的 Job
kubectl delete jobs/job-pod-failure-policy-failjob
叢集會自動清理 Pod。
使用 Pod 故障策略忽略 Pod 中斷
透過以下示例,你可以學習如何使用 Pod 故障策略來忽略 Pod 中斷,避免其增加 Pod 重試計數器以達到 .spec.backoffLimit
限制。
注意
此示例的時機很重要,因此你可能希望在執行之前閱讀這些步驟。為了觸發 Pod 中斷,在 Pod 正在節點上執行(自 Pod 排程起 90 秒內)時,排空該節點很重要。檢查以下清單:
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 https://k8s.io/examples/controllers/job-pod-failure-policy-ignore.yaml
執行此命令檢查 Pod 排程到的
nodeName
:nodeName=$(kubectl get pods -l job-name=job-pod-failure-policy-ignore -o jsonpath='{.items[0].spec.nodeName}')
排空節點以在 Pod 完成之前(90 秒內)驅逐 Pod:
kubectl drain nodes/$nodeName --ignore-daemonsets --grace-period=0
檢查
.status.failed
以檢視 Job 的計數器是否未遞增kubectl get jobs -l job-name=job-pod-failure-policy-ignore -o yaml
恢復排程節點
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 重啟。
檢查以下清單:
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 https://k8s.io/examples/controllers/job-pod-failure-policy-config-issue.yaml
請注意,映象配置錯誤,因為它不存在。
執行以下命令檢查 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
階段。原則上,這可能是一個瞬態問題,映象可以被拉取。但是,在這種情況下,映象不存在,因此我們透過自定義狀況來指示此事實。新增自定義狀況。首先透過執行以下命令準備補丁:
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
透過執行以下命令刪除 Pod 以將其轉換為
Failed
階段:kubectl delete pods/$podName
透過執行以下命令檢查 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
。
注意
在生產環境中,步驟 3 和 4 應由使用者提供的控制器自動執行。清理
刪除你建立的 Job
kubectl delete jobs/job-pod-failure-policy-config-issue
叢集會自動清理 Pod。
使用 Pod 故障策略避免每個索引不必要的 Pod 重試
為了避免每個索引不必要的 Pod 重啟,你可以使用 Pod 故障策略和每個索引的退避限制功能。本頁的這一部分展示瞭如何一起使用這些功能。
檢查以下清單:
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]
應用清單
kubectl create -f https://k8s.io/examples/controllers/job-backoff-limit-per-index-failindex.yaml
大約 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 故障策略匹配。
透過執行以下命令檢查 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 中斷終止之間找到平衡是很有問題的。