Kubernetes 提供了 Job 和 CronJob 兩種資源,分別用於管理一次性任務和週期性任務。相較於裸 Pod、ReplicaSet 和 DaemonSet,Job 更適合處理需可靠執行且在完成後終止的任務。Job 的特性包含任務永續性、狀態追蹤、可控的完成次數和平行度,以及暫停、還原和容錯機制。理解 Job 的不同型別,如固定完成次數、工作佇列和索引 Job,能更好地根據實際需求選擇合適的執行方式。進一步地,CronJob 建立在 Job 基礎上,透過 cron 格式定義排程規則,實作週期性任務的自動化管理,並提供更精細的控制選項,例如錯過排程的處理策略和平行控制。
第7章:批次作業(Batch Job)
批次作業模式適用於管理獨立的原子工作單元,能夠在分散式環境中可靠地執行至完成。本章根據Kubernetes的Job資源進行探討。
問題描述
在Kubernetes中,Pod是管理與執行容器的基本單元。然而,不同型別的Pod具有不同的特性:
- 裸Pod(Bare Pod):可手動建立Pod,但當執行Pod的節點故障時,Pod不會被重新啟動。這種方式主要用於開發或測試,不建議用於生產環境。
- ReplicaSet:用於建立和管理預期持續執行的Pod,例如執行網頁伺服器容器。它保證特定數量的相同Pod在任何時候都處於執行狀態。詳細內容請參考第11章「無狀態服務(Stateless Service)」。
- DaemonSet:在每個節點上執行一個Pod,用於管理平台功能,如監控、記錄彙總、儲存容器等。有關詳細資訊,請參閱第9章「守護程式服務(Daemon Service)」。
這些Pod的共同特點是代表長期執行的程式,不會在特定時間後停止。然而,在某些情況下,需要可靠地執行預定義的有限工作單元,然後關閉容器。為此,Kubernetes提供了Job資源。
解決方案
Kubernetes Job與ReplicaSet相似,都會建立一個或多個Pod並確保其成功執行。然而,Job與ReplicaSet的不同之處在於,當預期的Pod成功終止後,Job即視為完成,不會再啟動新的Pod。
Job定義範例
apiVersion: batch/v1
kind: Job
metadata:
name: random-generator
spec:
completions: 5
parallelism: 2
ttlSecondsAfterFinished: 300
template:
metadata:
name: random-generator
spec:
restartPolicy: OnFailure
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
command: [ "java", "RandomRunner", "/numbers.txt", "10000" ]
#### 內容解密:
completions: 5:指定Job需要成功執行的Pod數量為5。parallelism: 2:允許同時平行執行的Pod數量為2。ttlSecondsAfterFinished: 300:Job完成後,保留Pod的時間為300秒(5分鐘),之後將被垃圾回收。restartPolicy: OnFailure:指定當Pod失敗時的重啟策略為「失敗時重啟」。containers部分定義了執行Job的容器細節,包括使用的映像檔、名稱和執行的命令。
相較於ReplicaSet,Job定義中的.spec.template.spec.restartPolicy至關重要。對於Job而言,唯一允許的值是OnFailure或Never,而非預設的Always。
為何使用Job?
使用Job而非裸Pod有許多可靠性和可擴充套件性的優勢:
- 永續性:Job是一種持久化的任務,能夠在叢集重啟後繼續存在。
- 跟蹤完成情況:Job完成後不會被刪除,以便跟蹤其狀態。所建立的Pod同樣保留,用於檢查容器日誌等。
- 多次執行:透過
.spec.completions欄位,可以指定一個Pod需要成功完成的次數。 - 平行執行:透過
.spec.parallelism欄位,可以指定同時執行的Pod數量,以實作平行處理。 - 暫停與還原:可以透過設定
.spec.suspend欄位來暫停或還原Job。 - 容錯性:若節點故障或Pod被驅逐,Job會在新的健康節點上重新排程和執行Pod。
Job型別
根據.spec.completions和.spec.parallelism的不同設定,Job可以分為以下幾種型別:
- 單一Pod Job:當
.spec.completions和.spec.parallelism均未設定或設為1時,Job只會啟動一個Pod,並在該Pod成功終止後視為完成。
圖示說明
圖7-1展示了一個具有5個完成次數和2個平行度的Job執行過程。
此圖示清晰地展示了具有固定完成次數的平行批次作業的處理流程,能夠幫助讀者更好地理解Job的工作機制。
Kubernetes Job 資源管理與工作分配詳解
Kubernetes 中的 Job 資源是一種用於執行一次性任務的控制器,它能夠確保指定的 Pod 完成任務後終止。Job 可以用於多種場景,例如批次處理、資料處理、影片處理等。本文將詳細介紹 Kubernetes Job 的型別、工作分配方式以及相關的最佳實踐。
Job 的型別
Kubernetes 中的 Job 主要分為三種型別:固定完成次數的 Job、工作佇列 Job 和索引 Job。
固定完成次數的 Job
固定完成次數的 Job 需要指定 .spec.completions 欄位,表示需要完成的任務數量。可以設定 .spec.parallelism 欄位來控制平行執行的 Pod 數量,如果未設定,則預設為 1。這種 Job 在 .spec.completions 數量的 Pod 成功完成後被視為完成。
程式碼範例:固定完成次數的 Job
apiVersion: batch/v1
kind: Job
metadata:
name: fixed-completion-job
spec:
completions: 5
parallelism: 2
template:
spec:
containers:
- name: job-container
image: busybox
command: ["echo", "Hello Kubernetes Job!"]
restartPolicy: OnFailure
內容解密:
- apiVersion 和 kind:定義了 Kubernetes 資源的 API 版本和型別,這裡使用的是
batch/v1版本的 Job。 - metadata:包含了 Job 的後設資料,如名稱。
- spec:定義了 Job 的規格,包括完成次數(
completions)、平行度(parallelism)和 Pod 範本(template)。 - template.spec:定義了 Pod 的規格,包括容器映像、命令和重啟策略。
工作佇列 Job
工作佇列 Job 不需要指定 .spec.completions,而是透過 .spec.parallelism 控制平行執行的 Pod 數量。這種 Job 在至少一個 Pod 成功終止且所有其他 Pod 終止後被視為完成。工作佇列 Job 需要 Pod 之間的協調,以確定每個 Pod 的工作內容。
程式碼範例:工作佇列 Job
apiVersion: batch/v1
kind: Job
metadata:
name: work-queue-job
spec:
parallelism: 3
template:
spec:
containers:
- name: job-container
image: busybox
command: ["sh", "-c", "echo Processing work item; sleep 5; echo Done"]
restartPolicy: OnFailure
內容解密:
- 平行度設定:透過
.spec.parallelism控制平行執行的 Pod 數量。 - 容器命令:模擬處理工作專案的過程,包括處理和等待。
- 重啟策略:設定為
OnFailure,表示在失敗時重啟 Pod。
索引 Job
索引 Job 是透過設定 .spec.completionMode 為 Indexed 來實作的,每個 Pod 會獲得一個與之關聯的索引,範圍從 0 到 .spec.completions - 1。這個索引可以透過環境變數 JOB_COMPLETION_INDEX 取得,應用程式可以使用這個索引來確定自己的工作內容。
程式碼範例:索引 Job
apiVersion: batch/v1
kind: Job
metadata:
name: indexed-job
spec:
completionMode: Indexed
completions: 5
parallelism: 5
template:
spec:
containers:
- name: job-container
image: alpine
command: ["sh", "-c", "start=$(expr $JOB_COMPLETION_INDEX * 10000); end=$(expr $JOB_COMPLETION_INDEX * 10000 + 10000); awk \"NR>=$start && NR<$end\" /logs/random.log > /logs/random-$JOB_COMPLETION_INDEX.txt"]
volumeMounts:
- name: log-volume
mountPath: /logs
restartPolicy: OnFailure
內容解密:
- completionMode:設定為
Indexed,表示這是一個索引 Job。 - completions 和 parallelism:設定完成次數和平行度。
- 容器命令:使用
JOB_COMPLETION_INDEX環境變數計算起始和結束行號,並使用awk命令處理檔案。
工作分配
在 Kubernetes 中,可以透過多種方式分配工作給不同的 Pod。對於工作佇列 Job,需要一個外部系統來提供工作項。而對於索引 Job,則可以透過索引來分配工作。
最佳實踐
- 選擇合適的 Job 型別:根據具體需求選擇固定完成次數的 Job、工作佇列 Job 或索引 Job。
- 合理設定平行度:根據叢集資源和任務需求,合理設定
.spec.parallelism。 - 使用索引 Job 處理靜態工作分配:當工作可以被靜態分配時,使用索引 Job 可以簡化實作。
週期性任務(Periodic Job)模式詳解
問題背景
在分散式系統和微服務架構的世界裡,應用程式互動正逐漸朝向即時和事件驅動的方向發展,主要透過HTTP和輕量級訊息傳遞來實作。然而,儘管軟體開發趨勢不斷演進,任務排程的需求依然存在,且具有悠久的歷史。週期性任務(Periodic Job)被廣泛應用於自動化系統維護、行政任務,以及需要定期執行的業務應用中。典型的例子包括企業間透過檔案傳輸進行整合、透過資料函式庫輪詢進行應用程式整合、傳送電子報郵件,以及清理和歸檔舊檔案等任務。
傳統上,處理週期性任務的方式是使用專門的排程軟體或cron。然而,專門的軟體對於簡單的應用場景可能過於昂貴,而執行在單一伺服器上的cron任務則難以維護,並且存在單點故障的問題。因此,開發者往往傾向於自行實作解決方案,以同時處理排程和業務邏輯的需求。例如,在Java生態系中,開發者可能會使用Quartz、Spring Batch等函式庫,或是利用ScheduledThreadPoolExecutor類別來執行定時任務。然而,這種做法的主要挑戰在於如何使排程功能具備彈性和高用性,這通常需要耗費大量的資源。此外,這種方法還要求整個應用程式具備高用性,通常需要執行多個應使用案例項,並確保只有一個例項處於活躍狀態並執行排程任務,這涉及到長官者選舉(leader election)和其他分散式系統的挑戰。
最終,一個簡單的服務,如每天複製幾個檔案的任務,可能會需要多個節點、分散式長官者選舉機制等複雜的架構。Kubernetes的CronJob實作有效地解決了這些問題,它允許使用熟悉的cron格式來排程Job資源,讓開發者能夠專注於實作需要執行的任務,而無需關心定時排程的實作細節。
解決方案
在第7章「批次任務(Batch Job)」中,我們探討了Kubernetes Job的使用案例和功能。這些內容同樣適用於本章,因為CronJob是建立在Job之上的。CronJob例項類別似於Unix crontab(cron表格)中的一行,用於管理Job的時間相關方面。它允許在指定的時間點週期性地執行Job。範例8-1展示了一個CronJob資源的定義。
範例8-1:CronJob資源定義
apiVersion: batch/v1
kind: CronJob
metadata:
name: random-generator
spec:
schedule: "*/3 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
command: [ "java", "RandomRunner", "/numbers.txt", "10000" ]
restartPolicy: OnFailure
內容解密:
apiVersion和kind定義了 Kubernetes 資源的版本和型別,這裡是CronJob。metadata.name指定了 CronJob 的名稱。spec.schedule使用 cron 格式定義了 Job 的執行排程,這裡設定為每3分鐘執行一次。jobTemplate.spec定義了要執行的 Job 的範本,包括容器映像檔、命令等,與普通的 Job 定義相同。restartPolicy設定為OnFailure,表示當容器失敗時會重啟。
除了Job規格之外,CronJob還有額外的欄位來定義其時間相關的屬性:
.spec.schedule:用於指定Job的排程規則,例如每小時執行一次的0 * * * *。也支援像@daily或@hourly這樣的簡寫。.spec.startingDeadlineSeconds:用於指定Job錯過排程時間後開始執行的截止時間(以秒為單位)。如果因資源不足或其他依賴缺失導致Job無法在預定時間執行,可以設定此欄位來決定是否跳過該次執行。.spec.concurrencyPolicy:定義瞭如何管理由同一個CronJob建立的多個Job之間的平行執行。預設行為是允許平行執行,但也可以設定為禁止平行執行或取消當前正在執行的Job並啟動新的Job。.spec.suspend:用於暫停後續的Job執行,但不會影響已經開始執行的Job。.spec.successfulJobsHistoryLimit和.spec.failedJobsHistoryLimit:用於指定保留多少成功和失敗的Job記錄,以便於稽核。
討論
CronJob是一個非常專門化的Kubernetes資源,它適用於具有時間維度的任務。儘管它不是一個通用型的資源,但它很好地展示了Kubernetes如何將不同的功能組合起來,以支援非雲原生(cloud-native)的應用場景。當CronJob與其他Kubernetes資源(如Pod、容器資源隔離等)結合使用時,它能夠成為一個非常強大的任務排程系統,使開發者能夠專注於業務邏輯的實作,而無需擔心排程本身的實作。
此圖示說明瞭 CronJob 與其他 Kubernetes 元件之間的關係:
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes 批次與週期任務管理
package "Kubernetes Cluster" {
package "Control Plane" {
component [API Server] as api
component [Controller Manager] as cm
component [Scheduler] as sched
database [etcd] as etcd
}
package "Worker Nodes" {
component [Kubelet] as kubelet
component [Kube-proxy] as proxy
package "Pods" {
component [Container 1] as c1
component [Container 2] as c2
}
}
}
api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2
note right of api
核心 API 入口
所有操作經由此處
end note
@enduml內容解密:
- Kubernetes CronJob 管理 Job 的排程。
- Job 定義了要執行的任務,並由 Kubernetes 建立 Pod 來執行這些任務。
- Pod 中包含了容器(Container),實際執行業務邏輯。