一個工作會建立一個或多個 Pod,並會持續重試執行這些 Pod,直到指定數量的 Pod 成功終止。當 Pod 成功完成時,工作會追蹤這些成功的完成。當達到指定數量的成功完成時,該任務(即工作)就完成了。刪除一個工作會清理它所建立的 Pod。暫停一個工作會刪除其活躍的 Pod,直到該工作再次恢復。
一個簡單的案例是建立一個工作物件,以便可靠地執行一個 Pod 直到完成。如果第一個 Pod 失敗或被刪除(例如由於節點硬體故障或節點重啟),該工作物件將啟動一個新的 Pod。
您也可以使用工作來平行執行多個 Pod。
如果您想按排程執行工作(單一任務或多個平行任務),請參閱 CronJob。
這是一個工作設定的範例。它計算圓周率 π 到 2000 位並列印出來。它大約需要 10 秒鐘才能完成。
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
您可以使用此命令執行範例
kubectl apply -f https://kubernetes.club.tw/examples/controllers/job.yaml
輸出類似於此
job.batch/pi created
使用 kubectl 檢查工作的狀態
Name: pi
Namespace: default
Selector: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
Labels: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name=pi
...
Annotations: batch.kubernetes.io/job-tracking: ""
Parallelism: 1
Completions: 1
Start Time: Mon, 02 Dec 2019 15:20:11 +0200
Completed At: Mon, 02 Dec 2019 15:21:16 +0200
Duration: 65s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name=pi
Containers:
pi:
Image: perl:5.34.0
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 21s job-controller Created pod: pi-xf9p4
Normal Completed 18s job-controller Job completed
apiVersion: batch/v1
kind: Job
metadata:
annotations: batch.kubernetes.io/job-tracking: ""
...
creationTimestamp: "2022-11-10T17:53:53Z"
generation: 1
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
name: pi
namespace: default
resourceVersion: "4751"
uid: 204fb678-040b-497f-9266-35ffa8716d14
spec:
backoffLimit: 4
completionMode: NonIndexed
completions: 1
parallelism: 1
selector:
matchLabels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
suspend: false
template:
metadata:
creationTimestamp: null
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
spec:
containers:
- command:
- perl
- -Mbignum=bpi
- -wle
- print bpi(2000)
image: perl:5.34.0
imagePullPolicy: IfNotPresent
name: pi
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Never
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
active: 1
ready: 0
startTime: "2022-11-10T17:53:57Z"
uncountedTerminatedPods: {}
要查看工作的已完成 Pod,請使用 kubectl get pods。
要以機器可讀的格式列出屬於某個工作的所有 Pod,您可以使用類似這樣的命令
pods=$(kubectl get pods --selector=batch.kubernetes.io/job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
輸出類似於此
pi-5rwd7
在這裡,選擇器與工作的選擇器相同。--output=jsonpath 選項指定了一個表達式,其中包含返回列表中每個 Pod 的名稱。
查看其中一個 Pod 的標準輸出
kubectl logs $pods
查看工作日誌的另一種方式
kubectl logs jobs/pi
輸出類似於此
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
與所有其他 Kubernetes 設定一樣,工作需要 apiVersion、kind 和 metadata 欄位。
當控制平面為工作建立新的 Pod 時,工作的 .metadata.name 是命名這些 Pod 的基礎的一部分。工作的名稱必須是有效的 DNS 子網域 值,但這可能會對 Pod 的主機名稱產生意外結果。為了獲得最佳相容性,名稱應遵循 DNS 標籤 更嚴格的規則。即使名稱是 DNS 子網域,其長度也不得超過 63 個字元。
工作也需要一個 .spec 區塊。
工作標籤會以 batch.kubernetes.io/ 作為 job-name 和 controller-uid 的前綴。
.spec.template 是 .spec 中唯一必需的欄位。
.spec.template 是一個 Pod 範本。它與 Pod 具有完全相同的架構,只是它是巢狀的,並且沒有 apiVersion 或 kind 欄位。
除了 Pod 的必填欄位外,工作中的 Pod 範本必須指定適當的標籤(請參閱 Pod 選擇器)和適當的重啟策略。
僅允許 RestartPolicy 等於 Never 或 OnFailure。
.spec.selector 欄位是可選的。在幾乎所有情況下,您都不應指定它。請參閱 指定您自己的 Pod 選擇器 章節。
有三種主要任務類型適合作為工作執行
.spec.completions 指定一個非零正值。.spec.completions 個 Pod 成功時,即告完成。.spec.completionMode="Indexed" 時,每個 Pod 會在 0 到 .spec.completions-1 範圍內獲得一個不同的索引。.spec.completions,預設為 .spec.parallelism。對於 *非平行* 工作,您可以不設定 .spec.completions 和 .spec.parallelism。當兩者都未設定時,兩者都預設為 1。
對於 *固定完成計數* 工作,您應將 .spec.completions 設定為所需完成的數量。您可以設定 .spec.parallelism,或者不設定它,它將預設為 1。
對於 *工作佇列* 工作,您必須不設定 .spec.completions,並將 .spec.parallelism 設定為非負整數。
有關如何使用不同類型工作的更多資訊,請參閱 工作模式 章節。
請求的平行度 (.spec.parallelism) 可以設定為任何非負值。如果未指定,則預設為 1。如果指定為 0,則工作會有效地暫停,直到其值增加為止。
實際平行度(任何時刻執行的 Pod 數量)可能多於或少於請求的平行度,原因有很多
.spec.parallelism 值會被有效忽略。ResourceQuota、缺乏權限等)未能建立 Pod,則實際執行的 Pod 可能會少於請求的數量。Kubernetes v1.24 [stable]具有 *固定完成計數* 的工作——即 .spec.completions 不為空的工作——可以有一個在 .spec.completionMode 中指定的完成模式
NonIndexed(預設):當有 .spec.completions 個 Pod 成功完成時,該工作被視為完成。換句話說,每個 Pod 的完成都是彼此同質的。請注意,.spec.completions 為空的工作隱含為 NonIndexed。
Indexed:工作的 Pod 會獲得一個相關的完成索引,從 0 到 .spec.completions-1。該索引可透過四種機制取得
batch.kubernetes.io/job-completion-index。batch.kubernetes.io/job-completion-index(適用於 v1.28 及更高版本)。請注意,必須啟用功能門 PodIndexLabel 才能使用此標籤,並且它預設為啟用。$(job-name)-$(index)。當您將索引工作與 服務 結合使用時,工作中的 Pod 可以使用確定性主機名稱透過 DNS 互相定址。有關如何配置此項的更多資訊,請參閱 具有 Pod 對 Pod 通訊的工作。JOB_COMPLETION_INDEX 中。當每個索引都有一個成功完成的 Pod 時,該工作被視為完成。有關如何使用此模式的更多資訊,請參閱 用於靜態工作分配的平行處理的索引工作。
Kubernetes v1.36 [alpha] (預設停用)當啟用 WorkloadWithJob 功能門時,工作控制器會在建立任何 Pod 之前,自動為 符合條件的平行工作 建立 工作負載 (Workload) 和 PodGroup 物件。這使得原生 群組排程 (gang scheduling) 成為可能,即工作中所有 Pod 要麼一起排程,要麼都不排程。
當工作符合以下所有條件時,工作控制器會建立一個具有 群組排程策略 的工作負載 (Workload)
.spec.parallelism 大於 1.spec.completionMode 為 Indexed.spec.parallelism 等於 .spec.completions.spec.template.spec.schedulingGroup 未設定不符合這些條件的工作會繼續獨立排程 Pod,並且不建立 Workload 或 PodGroup。
例如,以下工作執行 8 個平行的索引工作者。當此功能啟用時,工作控制器會在建立任何 Pod 之前建立一個帶有 minCount: 8 的 Workload 和 PodGroup,確保所有 8 個工作者一起排程。
apiVersion: batch/v1
kind: Job
metadata:
name: distributed-training
namespace: training
spec:
parallelism: 8
completions: 8
completionMode: Indexed
template:
spec:
restartPolicy: Never
containers:
- name: trainer
image: training-image:latest
resources:
limits:
nvidia.com/gpu: 1
當工作控制器處理此工作時,它會自動執行以下操作:
podGroupTemplate,其中帶有 群組排程策略,其中 minCount 等於工作負載的平行度。spec.schedulingGroup.podGroupName 設定為 PodGroup 的名稱,將每個 Pod 連結到其排程群組。這些物件的發現基於規格參考 (controllerRef 和 podGroupTemplateRef)。
工作負載 (Workload) 和 PodGroup 由工作擁有(透過 ownerReferences),並在工作刪除時自動進行垃圾回收。
如果工作的 Pod 範本已經設定了 spec.schedulingGroup,則工作控制器不會建立 Workload 或 PodGroup 物件。這允許 JobSet 等高階控制器自行管理 Workload 和 PodGroup 的生命週期。
由 CronJob 建立的工作在其 PodTemplate 中沒有設定 schedulingGroup。如果 CronJob 建立的工作符合群組排程條件,工作控制器會為每個工作實例建立單獨的 Workload 和 PodGroup。
PodGroup。工作中所有的 Pod 都屬於同一個排程群組。minCount 是不可變的。對於使用群組排程的工作,對 .spec.parallelism 的更新將被拒絕。有關此限制的詳細資訊,請參閱 彈性索引工作。Workload 和 PodGroup 物件;它們在暫停時不會被刪除,在恢復時也不會被重新建立。Pod 中的容器可能會因多種原因失敗,例如其中程序以非零退出碼退出,或容器因超出記憶體限制而被殺死等。如果發生這種情況,並且 .spec.template.spec.restartPolicy = "OnFailure",則 Pod 會留在節點上,但容器會重新執行。因此,您的程式需要處理在本機重新啟動的情況,否則應指定 .spec.template.spec.restartPolicy = "Never"。有關 restartPolicy 的更多資訊,請參閱 Pod 生命週期。
整個 Pod 也可能因多種原因而失敗,例如當 Pod 從節點中被驅逐(節點升級、重啟、刪除等),或者 Pod 的容器失敗且 .spec.template.spec.restartPolicy = "Never"。當 Pod 失敗時,工作控制器會啟動一個新的 Pod。這意味著您的應用程式需要處理在新 Pod 中重新啟動的情況。特別是,它需要處理前一次執行造成的暫存檔案、鎖定、不完整輸出等。
預設情況下,每個 Pod 失敗都會計入 .spec.backoffLimit 限制,請參閱 Pod 退避失敗策略。但是,您可以透過設定工作的 Pod 失敗策略 來客製化處理 Pod 失敗。
此外,您可以透過設定 .spec.backoffLimitPerIndex 欄位,為 索引式 工作的每個索引獨立計算 Pod 失敗(有關更多資訊,請參閱 每個索引的退避限制)。
請注意,即使您指定 .spec.parallelism = 1、.spec.completions = 1 和 .spec.template.spec.restartPolicy = "Never",同一個程式有時仍可能被啟動兩次。
如果您指定 .spec.parallelism 和 .spec.completions 都大於 1,則可能會有許多 Pod 同時執行。因此,您的 Pod 也必須能夠容忍並行。
如果您指定了 .spec.podFailurePolicy 欄位,工作控制器不會將正在終止的 Pod(即設定了 .metadata.deletionTimestamp 欄位的 Pod)視為失敗,直到該 Pod 達到終端狀態(其 .status.phase 為 Failed 或 Succeeded)。然而,一旦終止變得明顯,工作控制器就會建立一個替換 Pod。一旦 Pod 終止,工作控制器會評估相關工作的 .backoffLimit 和 .podFailurePolicy,將這個現在已終止的 Pod 納入考慮。
如果這些要求中的任何一個未滿足,工作控制器會將正在終止的 Pod 視為立即失敗,即使該 Pod 後來以 phase: "Succeeded" 終止。
在某些情況下,您希望在因配置中的邏輯錯誤等原因重試一定次數後使工作失敗。為此,請設定 .spec.backoffLimit 以指定在將工作視為失敗之前的重試次數。
.spec.backoffLimit 預設設定為 6,除非指定了 每個索引的退避限制(僅限索引式工作)。當指定 .spec.backoffLimitPerIndex 時,.spec.backoffLimit 預設為 2147483647 (MaxInt32)。
與工作相關聯的失敗 Pod 會由工作控制器以指數退避延遲(10 秒、20 秒、40 秒...)重新建立,上限為六分鐘。
重試次數透過兩種方式計算
.status.phase = "Failed" 的 Pod 數量。restartPolicy = "OnFailure" 時,所有 .status.phase 等於 Pending 或 Running 的 Pod 中所有容器的重試次數。如果任一計算達到 .spec.backoffLimit,則該工作被視為失敗。
restartPolicy = "OnFailure",請記住,一旦達到工作的退避限制,執行該工作的 Pod 將被終止。這可能會使調試工作的可執行檔更加困難。我們建議在調試工作時設定 restartPolicy = "Never",或使用日誌系統以確保失敗工作的輸出不會意外遺失。Kubernetes v1.33 [stable] (預設啟用)當您執行 索引式 工作時,您可以選擇為每個索引獨立處理 Pod 失敗的重試。為此,請設定 .spec.backoffLimitPerIndex 以指定每個索引的 Pod 失敗的最大數量。
當索引的每索引退避限制被超出時,Kubernetes 會將該索引視為失敗,並將其新增到 .status.failedIndexes 欄位。成功執行的 Pod 所屬的成功索引,無論您是否設定 backoffLimitPerIndex 欄位,都會記錄在 .status.completedIndexes 欄位中。
請注意,失敗的索引不會中斷其他索引的執行。一旦您為工作指定了每個索引的退避限制,並且所有索引都完成,如果其中至少一個索引失敗,工作控制器會透過在狀態中設定 Failed 條件來將整個工作標記為失敗。即使部分(甚至幾乎所有)索引都已成功處理,工作仍會被標記為失敗。
您還可以透過設定 .spec.maxFailedIndexes 欄位來限制被標記為失敗的索引的最大數量。當失敗索引的數量超過 maxFailedIndexes 欄位時,工作控制器會觸發終止該工作中所有剩餘的執行中 Pod。一旦所有 Pod 都終止,工作控制器會透過在工作狀態中設定 Failed 條件來將整個工作標記為失敗。
這是一個定義了 backoffLimitPerIndex 的工作範例宣告
apiVersion: batch/v1
kind: Job
metadata:
name: job-backoff-limit-per-index-example
spec:
completions: 10
parallelism: 3
completionMode: Indexed # required for the feature
backoffLimitPerIndex: 1 # maximal number of failures per index
maxFailedIndexes: 5 # maximal number of failed indexes before terminating the Job execution
template:
spec:
restartPolicy: Never # required for the feature
containers:
- name: example
image: python
command: # The jobs fails as there is at least one failed index
# (all even indexes fail in here), yet all indexes
# are executed as maxFailedIndexes is not exceeded.
- python3
- -c
- |
import os, sys
print("Hello world")
if int(os.environ.get("JOB_COMPLETION_INDEX")) % 2 == 0:
sys.exit(1)
在上述範例中,工作控制器允許每個索引重新啟動一次。當失敗索引的總數超過 5 時,則整個工作終止。
工作完成後,工作狀態如下所示
kubectl get -o yaml job job-backoff-limit-per-index-example
status:
completedIndexes: 1,3,5,7,9
failedIndexes: 0,2,4,6,8
succeeded: 5 # 1 succeeded pod for each of 5 succeeded indexes
failed: 10 # 2 failed pods (1 retry) for each of 5 failed indexes
conditions:
- message: Job has failed indexes
reason: FailedIndexes
status: "True"
type: FailureTarget
- message: Job has failed indexes
reason: FailedIndexes
status: "True"
type: Failed
工作控制器新增 FailureTarget 工作條件以觸發 工作的終止與清理。當所有工作 Pod 都終止後,工作控制器會新增 Failed 條件,其 reason 和 message 值與 FailureTarget 工作條件相同。有關詳細資訊,請參閱 工作 Pod 的終止。
此外,您可能希望將每索引退避與 Pod 失敗策略 一起使用。當使用每索引退避時,有一個新的 FailIndex 動作可用,它允許您避免在索引內進行不必要的重試。
Kubernetes v1.31 [穩定版](預設啟用)Pod 失敗策略,透過 .spec.podFailurePolicy 欄位定義,使您的叢集能夠根據容器退出碼和 Pod 條件來處理 Pod 失敗。
在某些情況下,您可能希望在處理 Pod 失敗時擁有比 Pod 退避失敗策略 更好的控制,後者是基於工作的 .spec.backoffLimit。以下是一些使用案例範例
.spec.backoffLimit 的重試限制。您可以在 .spec.podFailurePolicy 欄位中配置 Pod 失敗策略,以滿足上述使用案例。此策略可以根據容器退出碼和 Pod 條件來處理 Pod 失敗。
這是一個定義了 podFailurePolicy 的工作範例宣告
apiVersion: batch/v1
kind: Job
metadata:
name: job-pod-failure-policy-example
spec:
completions: 12
parallelism: 3
template:
spec:
restartPolicy: Never
containers:
- name: main
image: docker.io/library/bash:5
command: ["bash"] # example command simulating a bug which triggers the FailJob action
args:
- -c
- echo "Hello world!" && sleep 5 && exit 42
backoffLimit: 6
podFailurePolicy:
rules:
- action: FailJob
onExitCodes:
containerName: main # optional
operator: In # one of: In, NotIn
values: [42]
- action: Ignore # one of: Ignore, FailJob, Count
onPodConditions:
- type: DisruptionTarget # indicates Pod disruption
在上述範例中,Pod 失敗策略的第一條規則指定,如果 main 容器以退出碼 42 失敗,則該工作應被標記為失敗。以下是針對 main 容器的具體規則
backoffLimit,則 Pod 將被重新建立。如果達到 backoffLimit,則 **整個工作** 失敗。restartPolicy: Never,所以 kubelet 不會重新啟動該特定 Pod 中的 main 容器。Pod 失敗策略的第二條規則,為具有條件 DisruptionTarget 的失敗 Pod 指定 Ignore 動作,將 Pod 中斷排除在 .spec.backoffLimit 的重試限制之外。
以下是 API 的一些要求和語義
.spec.podFailurePolicy 欄位,您還必須將該工作的 Pod 範本定義為 .spec.restartPolicy 設定為 Never。spec.podFailurePolicy.rules 下指定的 Pod 失敗策略規則會依序評估。一旦某條規則符合 Pod 失敗,其餘規則將被忽略。如果沒有規則符合 Pod 失敗,則套用預設處理方式。spec.podFailurePolicy.rules[*].onExitCodes.containerName 中指定其名稱來將規則限制到特定容器。如果未指定,則該規則適用於所有容器。如果指定,它應與 Pod 範本中的某個容器或 initContainer 名稱匹配。spec.podFailurePolicy.rules[*].action 指定 Pod 失敗策略匹配時採取的動作。可能的值為FailJob:用於指示 Pod 的工作應標記為失敗,並且所有執行中的 Pod 都應終止。Ignore:用於指示不應增加 .spec.backoffLimit 的計數器,並且應建立一個替換 Pod。Count:用於指示應以預設方式處理 Pod。應增加 .spec.backoffLimit 的計數器。FailIndex:將此動作與 每個索引的退避限制 一起使用,以避免在失敗 Pod 的索引內進行不必要的重試。podFailurePolicy 時,工作控制器只會匹配處於 Failed 階段的 Pod。具有刪除時間戳但未處於終端階段(Failed 或 Succeeded)的 Pod 被視為仍在終止中。這意味著正在終止的 Pod 會保留一個 追蹤 finalizer,直到它們達到終端階段。自 Kubernetes 1.27 起,Kubelet 將已刪除的 Pod 轉換為終端階段(請參閱:Pod 階段)。這確保了已刪除的 Pod 其 finalizer 會被工作控制器移除。Failed 階段後才重新建立正在終止的 Pod。此行為類似於 podReplacementPolicy: Failed。有關更多資訊,請參閱 Pod 替換策略。當您使用 podFailurePolicy,且工作因 Pod 符合帶有 FailJob 動作的規則而失敗時,工作控制器會透過新增 FailureTarget 條件來觸發工作終止程序。有關更多詳細資訊,請參閱 工作的終止與清理。
建立索引式工作時,您可以根據成功完成的 Pod 來定義何時將工作宣告為成功,方法是使用 .spec.successPolicy。
預設情況下,當成功完成的 Pod 數量等於 .spec.completions 時,工作即告成功。以下是您可能希望對宣告工作成功擁有額外控制權的一些情況
您可以在 .spec.successPolicy 欄位中配置成功策略,以滿足上述使用案例。此策略可以根據成功的 Pod 處理工作成功。在工作符合成功策略後,工作控制器會終止殘留的 Pod。成功策略由規則定義。每個規則可以採用以下形式之一
succeededIndexes 時,一旦 succeededIndexes 中指定的所有索引成功,工作控制器會將工作標記為成功。succeededIndexes 必須是 0 到 .spec.completions-1 之間的區間列表。succeededCount 時,一旦成功索引的數量達到 succeededCount,工作控制器會將工作標記為成功。succeededIndexes 和 succeededCount 時,一旦在 succeededIndexes 中指定索引子集中的成功索引數量達到 succeededCount,工作控制器會將工作標記為成功。請注意,當您在 .spec.successPolicy.rules 中指定多個規則時,工作控制器會依序評估這些規則。一旦工作符合某條規則,工作控制器會忽略其餘規則。
這是一個帶有 successPolicy 的工作範例宣告
apiVersion: batch/v1
kind: Job
metadata:
name: job-success
spec:
parallelism: 10
completions: 10
completionMode: Indexed # Required for the success policy
successPolicy:
rules:
- succeededIndexes: 0,2-3
succeededCount: 1
template:
spec:
containers:
- name: main
image: python
command: # Provided that at least one of the Pods with 0, 2, and 3 indexes has succeeded,
# the overall Job is a success.
- python3
- -c
- |
import os, sys
if os.environ.get("JOB_COMPLETION_INDEX") == "2":
sys.exit(0)
else:
sys.exit(1)
restartPolicy: Never
在上述範例中,同時指定了 succeededIndexes 和 succeededCount。因此,當指定索引中的任一個(0、2 或 3)成功時,工作控制器會將工作標記為成功並終止殘留的 Pod。符合成功策略的工作會獲得帶有 SuccessPolicy 原因的 SuccessCriteriaMet 條件。在發出移除殘留 Pod 的指令後,工作會獲得 Complete 條件。
請注意,succeededIndexes 以連字號分隔的區間表示。數字列出方式是透過序列的第一個和最後一個元素,並以連字號分隔。
.spec.backoffLimit 和 .spec.podFailurePolicy 時,一旦工作符合其中任何一個策略,工作控制器會遵守終止策略並忽略成功策略。當工作完成時,不會再建立 Pod,但這些 Pod 通常 也不會被刪除。保留它們可以讓您仍然查看已完成 Pod 的日誌,以檢查錯誤、警告或其他診斷輸出。工作物件在完成後也會保留,以便您可以查看其狀態。使用者應在記錄其狀態後刪除舊工作。使用 kubectl 刪除工作(例如 kubectl delete jobs/pi 或 kubectl delete -f ./job.yaml)。當您使用 kubectl 刪除工作時,它建立的所有 Pod 也會被刪除。
預設情況下,工作將不中斷地執行,除非 Pod 失敗 (restartPolicy=Never) 或容器錯誤退出 (restartPolicy=OnFailure),此時工作會依照上述 .spec.backoffLimit 處理。一旦達到 .spec.backoffLimit,工作將被標記為失敗,並且任何執行中的 Pod 都將被終止。
終止工作的另一種方法是設定活躍期限 (active deadline)。透過將工作的 .spec.activeDeadlineSeconds 欄位設定為秒數來實現。activeDeadlineSeconds 適用於工作的持續時間,無論建立多少個 Pod。一旦工作達到 activeDeadlineSeconds,所有執行中的 Pod 都會被終止,並且工作狀態將變為 type: Failed,其 reason: DeadlineExceeded。
請注意,工作的 .spec.activeDeadlineSeconds 優先於其 .spec.backoffLimit。因此,正在重試一個或多個失敗 Pod 的工作,一旦達到 activeDeadlineSeconds 指定的時間限制,即使尚未達到 backoffLimit,也不會部署額外的 Pod。
範例:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-timeout
spec:
backoffLimit: 5
activeDeadlineSeconds: 100
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
請注意,工作規格和工作中的 Pod 範本規格 都具有 activeDeadlineSeconds 欄位。請確保您在適當的層級設定此欄位。
請記住,restartPolicy 適用於 Pod,而不是工作本身:一旦工作狀態為 type: Failed,就不會自動重啟工作。也就是說,透過 .spec.activeDeadlineSeconds 和 .spec.backoffLimit 啟動的工作終止機制會導致永久性的工作失敗,需要手動干預才能解決。
工作有兩種可能的終端狀態,每種狀態都對應一個工作條件
CompleteFailed工作因以下原因失敗
.spec.backoffLimit。有關詳細資訊,請參閱 Pod 退避失敗策略。.spec.activeDeadlineSeconds.spec.backoffLimitPerIndex 的索引式工作具有失敗的索引。有關詳細資訊,請參閱 每個索引的退避限制。spec.maxFailedIndexes。有關詳細資訊,請參閱 每個索引的退避限制.spec.podFailurePolicy 中具有 FailJob 動作的規則。有關 Pod 失敗策略規則如何影響失敗評估的詳細資訊,請參閱 Pod 失敗策略。工作因以下原因成功
.spec.completions.spec.successPolicy 中指定的條件。有關詳細資訊,請參閱 成功策略。在 Kubernetes v1.31 及更高版本中,工作控制器會延遲新增終端條件 Failed 或 Complete,直到所有工作 Pod 都終止。
在 Kubernetes v1.30 及更早版本中,工作控制器會在工作終止程序觸發且所有 Pod finalizer 被移除後立即新增 Complete 或 Failed 工作終端條件。然而,在新增終端條件時,某些 Pod 可能仍在執行或終止中。
在 Kubernetes v1.31 及更高版本中,控制器只在所有 Pod 終止 *之後* 才新增工作終端條件。您可以透過使用 JobManagedBy 和 JobPodReplacementPolicy(兩者預設均啟用)功能門 來控制此行為。
工作控制器會將 FailureTarget 條件或 SuccessCriteriaMet 條件新增到工作中,以在工作符合成功或失敗條件後觸發 Pod 終止。
諸如 terminationGracePeriodSeconds 之類的因素可能會增加從工作控制器新增 FailureTarget 條件或 SuccessCriteriaMet 條件到所有工作 Pod 終止且工作控制器新增 終端條件(Failed 或 Complete)之間的時間量。
您可以使用 FailureTarget 或 SuccessCriteriaMet 條件來評估工作是失敗還是成功,而無需等待控制器新增終端條件。
例如,您可能希望決定何時建立替換工作以替換失敗的工作。如果您在 FailureTarget 條件出現時替換失敗的工作,您的替換工作會更快執行,但可能導致失敗的工作和替換工作的 Pod 同時執行,佔用額外的計算資源。
或者,如果您的叢集資源容量有限,您可以選擇等到 Failed 條件出現在工作上,這會延遲您的替換工作,但能確保您透過等待所有失敗的 Pod 被移除來節省資源。
已完成的工作通常不再需要留在系統中。將它們保留在系統中會對 API 伺服器造成壓力。如果工作由 CronJobs 等高階控制器直接管理,則 CronJobs 可以根據指定的基於容量的清理策略來清理這些工作。
Kubernetes v1.23 [穩定]自動清理已完成工作(無論是 Complete 還是 Failed)的另一種方法是使用 TTL 控制器 為已完成資源提供的 TTL 機制,方法是指定工作的 .spec.ttlSecondsAfterFinished 欄位。
當 TTL 控制器清理工作時,它會級聯刪除該工作,即連同工作一起刪除其依賴物件,例如 Pod。請注意,當工作被刪除時,其生命週期保證,例如 finalizer,將被遵守。
例如
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
工作 pi-with-ttl 將在完成後 100 秒內符合自動刪除的資格。
如果該欄位設定為 0,工作將在完成後立即符合自動刪除的資格。如果該欄位未設定,則此工作在完成後不會被 TTL 控制器清理。
建議設定 ttlSecondsAfterFinished 欄位,因為非託管工作(您直接建立而非透過其他工作負載 API,例如 CronJob 間接建立的工作)預設刪除策略為 orphanDependents,這會導致由非託管工作建立的 Pod 在該工作完全刪除後仍然存在。儘管 控制平面 (control plane) 最終會在已刪除工作的 Pod 失敗或完成後 垃圾回收 這些 Pod,但有時這些殘留的 Pod 可能會導致叢集效能下降,最壞的情況下甚至可能導致叢集因這種下降而離線。
您可以使用 LimitRanges 和 ResourceQuotas 來限制特定命名空間可以消耗的資源量。
工作物件可用於處理一組獨立但相關的 *工作項目*。這些可能是要發送的電子郵件、要渲染的影格、要轉碼的檔案、要在 NoSQL 資料庫中掃描的鍵範圍等等。
在複雜系統中,可能有多個不同的工作項目集合。這裡我們只考慮使用者想要一起管理的一個工作項目集合——一個 *批次工作*。
平行計算有幾種不同的模式,每種模式都有其優點和缺點。權衡點在於
權衡總結如下,欄位 2 到 4 對應上述權衡。模式名稱也是範例和更詳細說明的連結。
| 模式 | 單一 Job 物件 | Pod 數量少於工作項目嗎? | 使用未修改的應用程式嗎? |
|---|---|---|---|
| 每個工作項目一個 Pod 的佇列 | ✓ | 有時 | |
| 具可變 Pod 數量的佇列 | ✓ | ✓ | |
| 具靜態工作分配的索引式 Job | ✓ | ✓ | |
| 帶有 Pod 到 Pod 通訊的工作 | ✓ | 有時 | 有時 |
| Job 範本擴展 | ✓ |
當您使用 .spec.completions 指定完成數時,由 Job 控制器建立的每個 Pod 都具有相同的 spec。這表示任務的所有 Pods 將具有相同的命令列、相同的映像檔、相同的磁碟區,以及(幾乎)相同的環境變數。這些模式是安排 Pods 處理不同工作的不同方式。
此表格顯示了每個模式的 .spec.parallelism 和 .spec.completions 所需設定。在此,W 是工作項目的數量。
| 模式 | .spec.completions | .spec.parallelism |
|---|---|---|
| 每個工作項目一個 Pod 的佇列 | W | 任何 |
| 具可變 Pod 數量的佇列 | null | 任何 |
| 具靜態工作分配的索引式 Job | W | 任何 |
| 帶有 Pod 到 Pod 通訊的工作 | W | W |
| Job 範本擴展 | 1 | 應為 1 |
Kubernetes v1.24 [stable]當 Job 建立時,Job 控制器會立即開始建立 Pods 以滿足 Job 的要求,並持續執行直到 Job 完成。然而,您可能希望暫時暫停 Job 的執行並稍後恢復,或者以暫停狀態啟動 Job,然後讓自訂控制器稍後決定何時啟動它們。
要暫停 Job,您可以將 Job 的 .spec.suspend 欄位更新為 true;稍後當您想再次恢復它時,將其更新為 false。建立一個 .spec.suspend 設定為 true 的 Job 將使其處於暫停狀態。
在 Kubernetes 1.35 或更高版本中,當 MutableSchedulingDirectivesForSuspendedJobs 功能閘道啟用時,.status.startTime 欄位會在 Job 暫停時被清除。
當 Job 從暫停中恢復時,其 .status.startTime 欄位將重設為目前時間。這表示當 Job 暫停和恢復時,.spec.activeDeadlineSeconds 計時器將停止並重設。
當您暫停 Job 時,任何狀態不為 Completed 的正在執行的 Pods 將會以 SIGTERM 訊號終止。Pod 的優雅終止期將被遵守,您的 Pod 必須在此期間處理此訊號。這可能涉及為以後儲存進度或撤銷變更。以這種方式終止的 Pods 將不計入 Job 的 completions 數。
處於暫停狀態的 Job 定義範例如下
kubectl get job myjob -o yaml
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
suspend: true
parallelism: 1
completions: 5
template:
spec:
...
您也可以透過使用命令列修補 Job 來切換 Job 的暫停狀態。
暫停啟用中的 Job
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":true}}'
恢復暫停的 Job
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":false}}'
Job 的狀態可用於判斷 Job 是否正在暫停中或過去是否曾被暫停
kubectl get jobs/myjob -o yaml
apiVersion: batch/v1
kind: Job
# .metadata and .spec omitted
status:
conditions:
- lastProbeTime: "2021-02-05T13:14:33Z"
lastTransitionTime: "2021-02-05T13:14:33Z"
status: "True"
type: Suspended
startTime: "2021-02-05T13:13:48Z"
類型為 "Suspended" 且狀態為 "True" 的 Job 條件表示 Job 正在暫停中;lastTransitionTime 欄位可用於判斷 Job 已暫停多久。如果該條件的狀態為 "False",則 Job 之前曾被暫停,現在正在執行。如果 Job 的狀態中不存在此類條件,則 Job 從未停止過。
當 Job 暫停和恢復時,也會建立事件。
kubectl describe jobs/myjob
Name: myjob
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 12m job-controller Created pod: myjob-hlrpl
Normal SuccessfulDelete 11m job-controller Deleted pod: myjob-hlrpl
Normal Suspended 11m job-controller Job suspended
Normal SuccessfulCreate 3s job-controller Created pod: myjob-jvb44
Normal Resumed 3s job-controller Job resumed
最後四個事件,特別是「Suspended」(已暫停)和「Resumed」(已恢復)事件,是直接切換 .spec.suspend 欄位的結果。在這兩個事件之間,我們看到沒有建立任何 Pods,但一旦 Job 恢復,Pod 的建立就重新開始了。
Kubernetes v1.27 [穩定版]在大多數情況下,平行 Job 會希望 Pods 在約束條件下執行,例如全部在同一可用區,或全部在 GPU 型號 x 或 y 上,而不是兩者混用。
暫停 欄位是實現這些語義的第一步。暫停允許自訂佇列控制器決定 Job 何時應該開始;然而,一旦 Job 取消暫停,自訂佇列控制器就無法影響 Job 的 Pods 實際上將被排程到哪裡。
此功能允許在 Job 啟動之前更新其排程指令,這使自訂佇列控制器能夠影響 Pod 的放置,同時將實際的 Pod 到節點指派工作卸載給 kube-scheduler。
Job 的 Pod 範本中可以更新的欄位包括節點親和性、節點選擇器、容忍度、標籤、註解和 排程閘道。
Kubernetes v1.36 [beta](預設啟用)在 Kubernetes 1.34 或更早版本中,只有從未取消暫停過的暫停中 Job 才允許變更 Pod 的排程指令。在 Kubernetes 1.35 中,當 MutableSchedulingDirectivesForSuspendedJobs 功能閘道啟用時,任何暫停中 Job 都允許這樣做。
此外,此功能閘道也啟用在 Job 暫停時清除 .status.startTime 欄位。
Kubernetes v1.36 [beta](預設啟用)叢集管理員可以在 Kubernetes 中定義準入控制,根據策略規則修改 Job 的資源請求或限制。
透過此功能,Kubernetes 也讓您可以修改 暫停中 Job 的 Pod 範本,以變更 Job 中 Pods 的資源需求。這與讓您一次更新一個正在執行的 Pod 資源的「即時 Pod 大小調整」不同。
設定新資源請求或限制的用戶端可以與最初建立 Job 的用戶端不同,並且不需要是叢集管理員。
通常,當您建立 Job 物件時,您不需要指定 .spec.selector。系統預設邏輯會在建立 Job 時新增此欄位。它會選擇一個不會與任何其他 Job 重疊的選擇器值。
然而,在某些情況下,您可能需要覆寫此自動設定的選擇器。為此,您可以指定 Job 的 .spec.selector。
執行此操作時請務必小心。如果您指定的標籤選擇器對該 Job 的 Pods 不唯一,並且符合不相關的 Pods,那麼不相關 Job 的 Pods 可能會被刪除,或者此 Job 可能會將其他 Pods 計為完成任務,或者一個或兩個 Job 可能會拒絕建立 Pods 或執行到完成。如果選擇了非唯一選擇器,那麼其他控制器(例如 ReplicationController)及其 Pods 也可能以不可預測的方式運行。當您指定 .spec.selector 時,Kubernetes 不會阻止您犯錯。
以下是您可能希望使用此功能的一個範例。
假設 Job old 已經在執行。您希望現有的 Pods 繼續執行,但希望它建立的其餘 Pods 使用不同的 Pod 範本,並且 Job 具有一個新名稱。您無法更新 Job,因為這些欄位不可更新。因此,您使用 kubectl delete jobs/old --cascade=orphan 刪除 Job old,但 讓它的 Pods 保持執行。在刪除之前,請記下它使用的選擇器。
kubectl get job old -o yaml
輸出類似於此
kind: Job
metadata:
name: old
...
spec:
selector:
matchLabels:
batch.kubernetes.io/controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
然後您建立一個名稱為 new 的新 Job,並明確指定相同的選擇器。由於現有的 Pods 具有標籤 batch.kubernetes.io/controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002,它們也由 Job new 控制。
您需要在新 Job 中指定 manualSelector: true,因為您沒有使用系統通常為您自動產生的選擇器。
kind: Job
metadata:
name: new
...
spec:
manualSelector: true
selector:
matchLabels:
batch.kubernetes.io/controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
新 Job 本身將具有與 a8f3d00d-c6d2-11e5-9f87-42010af00002 不同的 uid。設定 manualSelector: true 告訴系統您知道自己在做什麼,並允許這種不匹配。
Kubernetes v1.26 [穩定版]控制平面會追蹤屬於任何 Job 的 Pods,並注意是否有此類 Pod 從 API 伺服器中移除。為此,Job 控制器會建立帶有 finalizer batch.kubernetes.io/job-tracking 的 Pods。控制器僅在 Pods 已在 Job 狀態中被計算在內後才移除 finalizer,從而允許 Pods 被其他控制器或使用者移除。
Kubernetes v1.31 [穩定版](預設啟用)您可以透過同時變更 .spec.parallelism 和 .spec.completions,使其滿足 .spec.parallelism == .spec.completions,來擴展或縮減索引式 Job。縮減時,Kubernetes 會移除索引較高的 Pods。
彈性索引式 Job 的使用案例包括需要擴展索引式 Job 的批次工作負載,例如 MPI、Horovod、Ray 和 PyTorch 訓練 Job。
WorkloadWithJob 功能閘道啟用且 Job 符合 成批排程準則時,對 .spec.parallelism 的更新將被拒絕,因為 Workload 的 minCount 欄位是不可變的。要擴展成批排程的 Job,請刪除並使用新的平行度值重新建立它。Kubernetes v1.34 [穩定] (預設啟用)預設情況下,Job 控制器會在 Pods 失敗或正在終止(具有刪除時間戳記)時立即重新建立它們。這意味著,在給定時間,當某些 Pods 正在終止時,Job 的正在執行 Pods 數量可能大於 parallelism 或每個索引超過一個 Pod(如果您正在使用索引式 Job)。
您可以選擇僅當正在終止的 Pod 完全終止(具有 status.phase: Failed)時才建立替代 Pod。為此,請設定 .spec.podReplacementPolicy: Failed。預設的替換策略取決於 Job 是否設定了 podFailurePolicy。如果 Job 沒有定義 Pod 失敗策略,則省略 podReplacementPolicy 欄位會選擇 TerminatingOrFailed 替換策略:控制平面會在 Pod 刪除時立即建立替代 Pod(一旦控制平面看到此 Job 的 Pod 設定了 deletionTimestamp)。對於設定了 Pod 失敗策略的 Job,預設的 podReplacementPolicy 是 Failed,不允許其他值。請參閱 Pod 失敗策略 以了解更多關於 Job 的 Pod 失敗策略。
kind: Job
metadata:
name: new
...
spec:
podReplacementPolicy: Failed
...
如果您的叢集已啟用該功能閘道,您可以檢查 Job 的 .status.terminating 欄位。該欄位的值是歸 Job 擁有且目前正在終止的 Pods 數量。
kubectl get jobs/myjob -o yaml
apiVersion: batch/v1
kind: Job
# .metadata and .spec omitted
status:
terminating: 3 # three Pods are terminating and have not yet reached the Failed phase
Kubernetes v1.35 [stable](預設啟用)此功能允許您針對特定 Job 停用內建的 Job 控制器,並將 Job 的協調任務委託給外部控制器。
您可以透過為 spec.managedBy 欄位設定自訂值(任何非 kubernetes.io/job-controller 的值)來指示協調 Job 的控制器。該欄位的值是不可變的。
開發外部 Job 控制器時,請注意您的控制器需要以符合 Job 物件 API 規範和狀態欄位定義的方式運行。
請在 Job API 中詳細審查這些內容。我們也建議您執行 Job 物件的端到端一致性測試,以驗證您的實作。
最後,開發外部 Job 控制器時,請確保它不使用保留給內建控制器的 batch.kubernetes.io/job-tracking finalizer。
當 Pod 正在執行的節點重啟或失敗時,該 Pod 將被終止且不會重新啟動。然而,Job 會建立新的 Pods 來替換已終止的 Pods。因此,我們建議您使用 Job 而不是裸 Pod,即使您的應用程式只需要一個 Pod。
Job 與 Replication Controllers 互補。Replication Controller 管理不預期會終止的 Pods(例如網路伺服器),而 Job 管理預期會終止的 Pods(例如批次任務)。
如 Pod 生命週期 中所討論,Job 僅適用於 RestartPolicy 等於 OnFailure 或 Never 的 Pods。
RestartPolicy,預設值為 Always。另一種模式是單一 Job 建立一個 Pod,然後該 Pod 再建立其他 Pods,充當這些 Pods 的某種自訂控制器。這提供了最大的靈活性,但開始使用可能有些複雜,且與 Kubernetes 的整合度較低。
這種方法的優點是,整個流程獲得 Job 物件的完成保證,但又可以完全控制建立哪些 Pods 以及如何將工作分配給它們。
Job 是 Kubernetes REST API 的一部分。閱讀 Job 物件定義以了解 Job 的 API。CronJob 的資訊,您可以用它來定義一系列依排程執行的 Job,類似於 UNIX 工具 cron。podFailurePolicy 配置處理可重試和不可重試的 Pod 失敗。