這篇文章已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
Kubernetes 1.28:改進了 Job 的故障處理能力
此部落格討論 Kubernetes 1.28 中的兩項新功能,以改善批次使用者的 Jobs:Pod 取代策略 和 每個索引的回退限制。
這些功能延續了 Pod 失敗策略 啟動的努力,以改善 Job 中 Pod 失敗的處理方式。
Pod 取代策略
預設情況下,當 Pod 進入終止狀態(例如,由於搶佔或驅逐)時,Kubernetes 會立即建立一個取代 Pod。因此,兩個 Pod 會同時執行。在 API 術語中,當 Pod 具有 deletionTimestamp
並且其階段為 Pending
或 Running
時,Pod 會被視為正在終止。
在給定時間執行兩個 Pod 的情況,對於某些流行的機器學習框架(例如 TensorFlow 和 JAX)來說是有問題的,這些框架要求對於給定的索引,最多只能執行一個 Pod。如果對於給定的索引執行兩個 Pod,Tensorflow 會給出以下錯誤。
/job:worker/task:4: Duplicate task registration with task_name=/job:worker/replica:0/task:4
更多詳細資訊請參閱 (issue)。
在先前的 Pod 完全終止之前建立取代 Pod,也可能在資源稀少或預算緊張的叢集中引起問題,例如
- 叢集資源可能難以取得要排程的 Pod,因為 Kubernetes 可能需要很長時間才能找到可用的節點,直到現有的 Pod 完全終止。
- 如果啟用叢集自動擴展器,取代 Pod 可能會產生不希望的擴展。
您如何使用它?
這是一個 Alpha 功能,您可以透過在叢集中開啟 JobPodReplacementPolicy
功能閘道 來啟用它。
一旦在您的叢集中啟用此功能,您就可以透過建立一個新的 Job,並指定 podReplacementPolicy
欄位來使用它,如下所示
kind: Job
metadata:
name: new
...
spec:
podReplacementPolicy: Failed
...
在該 Job 中,Pods 只會在它們達到 Failed
階段時才被取代,而不是在它們正在終止時。
此外,您可以檢查 Job 的 .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)特別有用,它可以追蹤來自 Job 執行中 Pod 的配額,直到從目前正在終止的 Job 中回收資源為止。
請注意,當使用自訂 Pod 失敗策略 時,podReplacementPolicy: Failed
是預設值。
每個索引的回退限制
預設情況下,Indexed Jobs 的 Pod 失敗會計入重試的全域限制,由 .spec.backoffLimit
表示。這表示,如果存在持續失敗的索引,它會重複重新啟動,直到耗盡限制為止。一旦達到限制,整個 Job 將被標記為失敗,並且某些索引可能甚至永遠不會啟動。
這對於您想要獨立處理每個索引的 Pod 失敗的用例來說是有問題的。例如,如果您使用 Indexed Jobs 來執行整合測試,其中每個索引對應於一個測試套件。在這種情況下,您可能需要考慮可能的 flake 測試,允許每個套件進行 1 或 2 次重試。可能有一些有錯誤的套件,導致相應的索引持續失敗。在這種情況下,您可能更喜歡限制有錯誤套件的重試次數,同時允許其他套件完成。
此功能允許您
- 完成所有索引的執行,儘管某些索引失敗。
- 透過避免不必要地重試持續失敗的索引,更好地利用計算資源。
您如何使用它?
這是一個 Alpha 功能,您可以透過在叢集中開啟 JobBackoffLimitPerIndex
功能閘道 來啟用它。
一旦在您的叢集中啟用此功能,您就可以建立一個 Indexed Job,並指定 .spec.backoffLimitPerIndex
欄位。
範例
以下範例示範如何使用此功能來確保 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)
現在,在 Job 完成後檢查 Pods
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
此外,您可以查看該 Job 的狀態
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
,然後在啟動某些較高的索引之前,整個 Job 將被標記為失敗。
您如何了解更多資訊?
參與其中
這些功能由 SIG Apps 贊助。批次用例正在 批次工作組 中積極為 Kubernetes 使用者改進。工作組是相對短期的倡議,專注於特定目標。WG Batch 的目標是改善批次工作負載使用者的體驗,為批次處理用例提供支援,並增強常用用例的 Job API。如果您對此感興趣,請透過訂閱我們的 郵件列表 或在 Slack 上加入工作組。
致謝
與任何 Kubernetes 功能一樣,多人為完成此功能做出了貢獻,從測試和提交錯誤到審查程式碼。
如果沒有 Aldo Culquicondor (Google) 在整個 Kubernetes 生態系統中提供出色的領域知識和專業知識,我們將無法實現這些功能中的任何一個。