Jobs và CronJobs trong Kubernetes
Trong Kubernetes, Deployments và StatefulSets được thiết kế cho các workloads chạy liên tục — chúng luôn cố gắng duy trì một số lượng Pod nhất định. Nhưng nhiều tác vụ trong thực tế không cần chạy mãi mãi: xử lý một batch dữ liệu, chạy database migration, train một model ML, hoặc gửi email hàng loạt. Đây là lúc Jobs và CronJobs phát huy tác dụng.
1. Jobs là gì? Batch Workloads và Run-to-Completion
Một Job trong Kubernetes tạo ra một hoặc nhiều Pods với mục tiêu hoàn thành một tác vụ cụ thể. Khác với Deployment, Job theo dõi số lượng completions thành công — khi đủ số Pod hoàn thành, Job được coi là done.
Đặc điểm quan trọng của Jobs:
- Run-to-completion: Pod chạy xong và exit với code 0 nghĩa là thành công
- Retry tự động: Nếu Pod fail, Job tự tạo Pod mới theo
backoffLimit - Tracking completions: Job biết đã hoàn thành bao nhiêu trong tổng số cần thiết
- Parallelism: Nhiều Pod có thể chạy song song để tăng throughput
Ví dụ Job đơn giản nhất — tính số Pi:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-calculator
namespace: default
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
resources:
requests:
cpu: "250m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "128Mi"
restartPolicy: Never
backoffLimit: 4
Lưu ý restartPolicy: Never — với Jobs, bạn chỉ được dùng Never hoặc OnFailure, không được dùng Always.
2. Job Completion Modes
Kubernetes hỗ trợ ba completion modes cho Jobs, phù hợp với các use case khác nhau.
2.1 NonIndexed (Default)
Job hoàn thành khi đủ số completions thành công. Các Pods không có thứ tự — chúng đều làm cùng một công việc và Job cần đủ completions Pod thành công.
apiVersion: batch/v1
kind: Job
metadata:
name: nonindexed-parallel-job
spec:
completions: 5 # Cần 5 Pod hoàn thành thành công
parallelism: 2 # Chạy tối đa 2 Pod cùng lúc
completionMode: NonIndexed # Đây là default, có thể bỏ qua
template:
spec:
containers:
- name: worker
image: busybox:1.35
command: ["sh", "-c", "echo Processing task; sleep 10; echo Done"]
restartPolicy: Never
backoffLimit: 3
2.2 Indexed Jobs
Indexed Jobs là tính năng rất mạnh — mỗi Pod nhận được một index duy nhất từ 0 đến completions-1 thông qua biến môi trường JOB_COMPLETION_INDEX. Điều này lý tưởng cho data partitioning: mỗi Pod xử lý một phần dữ liệu xác định.
apiVersion: batch/v1
kind: Job
metadata:
name: indexed-data-processor
spec:
completions: 10 # 10 partitions
parallelism: 3 # Xử lý 3 partitions cùng lúc
completionMode: Indexed
template:
spec:
containers:
- name: data-processor
image: python:3.11-slim
command:
- python3
- -c
- |
import os
partition_id = int(os.environ['JOB_COMPLETION_INDEX'])
total_partitions = 10
# Xử lý dữ liệu từ partition partition_id
start = partition_id * 1000
end = start + 1000
print(f"Processing records {start} to {end}")
# ... thực tế sẽ query database hoặc đọc file
env:
- name: JOB_COMPLETION_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
restartPolicy: Never
backoffLimit: 6
Kubernetes tự động inject biến JOB_COMPLETION_INDEX vào mỗi Pod. Pod 0 xử lý partition 0, Pod 1 xử lý partition 1, v.v. — không bao giờ trùng lặp dù có Pod restart.
2.3 Work Queue
Với work queue pattern, nhiều Pod cùng lấy task từ một hàng đợi (Redis, RabbitMQ, SQS). Job hoàn thành khi queue rỗng và không còn Pod nào đang xử lý.
apiVersion: batch/v1
kind: Job
metadata:
name: queue-worker
spec:
parallelism: 4 # 4 workers đồng thời
# completions không set = work queue mode (hoàn thành khi 1 Pod exit 0)
template:
spec:
containers:
- name: worker
image: my-queue-worker:v1.2
env:
- name: QUEUE_URL
value: "redis://redis-service:6379/queue:tasks"
- name: MAX_TASKS
value: "100"
resources:
requests:
cpu: "500m"
memory: "256Mi"
restartPolicy: OnFailure
3. Job Parameters Chi Tiết
Hiểu rõ các parameters của Job giúp bạn tối ưu cho từng use case:
- completions: Tổng số Pod cần hoàn thành thành công. Mặc định là 1.
- parallelism: Số Pod tối đa chạy đồng thời. Mặc định là 1.
- backoffLimit: Số lần retry trước khi Job bị đánh dấu failed. Mặc định là 6.
- activeDeadlineSeconds: Thời gian tối đa (giây) Job được phép chạy. Vượt quá → Job bị terminate.
- ttlSecondsAfterFinished: Xóa Job (và Pods) sau N giây kể từ khi hoàn thành.
apiVersion: batch/v1
kind: Job
metadata:
name: time-limited-job
spec:
completions: 3
parallelism: 3
backoffLimit: 2
activeDeadlineSeconds: 600 # Job phải xong trong 10 phút
ttlSecondsAfterFinished: 3600 # Xóa sau 1 giờ
template:
spec:
containers:
- name: worker
image: busybox:1.35
command: ["sh", "-c", "sleep 30 && echo completed"]
restartPolicy: Never
4. Pod Failure Policies (K8s 1.31+)
Từ Kubernetes 1.31, Pod Failure Policy cho phép bạn định nghĩa hành vi chi tiết khi Pod fail — không phải lúc nào cũng nên retry.
apiVersion: batch/v1
kind: Job
metadata:
name: job-with-failure-policy
spec:
completions: 5
parallelism: 2
backoffLimit: 6
podFailurePolicy:
rules:
# Nếu Pod exit với code 42 (business error), đừng retry — fail ngay
- action: FailJob
onExitCodes:
containerName: main
operator: In
values: [42]
# Nếu node bị preempt (OOM, spot interruption), ignore và retry
- action: Ignore
onPodConditions:
- type: DisruptionTarget
# Các lỗi khác: retry như bình thường
- action: Count
onExitCodes:
operator: NotIn
values: [0, 42]
template:
spec:
containers:
- name: main
image: my-batch-processor:v2
command: ["./process"]
restartPolicy: Never
Các action có thể dùng:
- FailJob: Dừng toàn bộ Job ngay lập tức, đánh dấu failed
- Ignore: Không tính vào backoffLimit, tạo Pod mới
- Count: Tính vào backoffLimit như bình thường (default behavior)
5. Job TTL — Dọn Dẹp Tự Động
Jobs và Pods của chúng sẽ tồn tại mãi sau khi hoàn thành nếu không có cơ chế dọn dẹp. Dùng ttlSecondsAfterFinished để tự động xóa:
apiVersion: batch/v1
kind: Job
metadata:
name: cleanup-demo
spec:
ttlSecondsAfterFinished: 300 # Xóa 5 phút sau khi xong (kể cả failed)
template:
spec:
containers:
- name: task
image: busybox:1.35
command: ["echo", "Hello from Job"]
restartPolicy: Never
Bạn cũng có thể patch Jobs hiện có: kubectl patch job old-job -p '{"spec":{"ttlSecondsAfterFinished":0}}' — điều này xóa Job ngay lập tức.
6. CronJobs — Lên Lịch Tác Vụ
CronJob tự động tạo Jobs theo lịch định kỳ, sử dụng cú pháp cron quen thuộc.
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-report
namespace: production
spec:
schedule: "0 2 * * *" # 2 giờ sáng mỗi ngày
timeZone: "Asia/Ho_Chi_Minh" # GA từ K8s 1.27
concurrencyPolicy: Forbid # Không chạy job mới nếu job cũ đang chạy
startingDeadlineSeconds: 300 # Nếu trễ quá 5 phút, bỏ qua
successfulJobsHistoryLimit: 3 # Giữ 3 successful jobs gần nhất
failedJobsHistoryLimit: 1 # Giữ 1 failed job gần nhất
jobTemplate:
spec:
ttlSecondsAfterFinished: 86400 # Xóa sau 24 giờ
template:
spec:
containers:
- name: report-generator
image: my-report-app:v1.5
command: ["python", "generate_report.py", "--date", "yesterday"]
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: host
restartPolicy: OnFailure
6.1 CronJob Timezone Support (GA K8s 1.27)
Trước K8s 1.27, tất cả CronJobs đều dùng UTC của controller. Từ K8s 1.27, timeZone field là GA — bạn có thể chỉ định timezone bất kỳ theo IANA timezone database:
spec:
schedule: "0 9 * * 1-5" # 9 giờ sáng thứ 2-6
timeZone: "Asia/Ho_Chi_Minh" # Vietnam timezone (UTC+7)
Các timezone phổ biến:
Asia/Ho_Chi_Minh— Việt Nam (UTC+7)Asia/Singapore— Singapore (UTC+8)America/New_York— Eastern USEurope/London— UKUTC— Coordinated Universal Time
6.2 ConcurrencyPolicy
Điều quan trọng cần quyết định: phải làm gì nếu một Job cũ chưa xong khi đến lịch chạy Job mới?
- Allow (default): Tạo Job mới kể cả khi Job cũ đang chạy — cẩn thận với race conditions
- Forbid: Bỏ qua Job mới, Job cũ vẫn tiếp tục
- Replace: Xóa Job cũ, tạo Job mới thay thế
7. JobSet — CNCF Project cho Distributed Jobs
JobSet là một CNCF project (hiện đang ở giai đoạn Sandbox) được thiết kế để điều phối nhiều Jobs có quan hệ phụ thuộc nhau. Đây là công cụ lý tưởng cho distributed ML training pipelines.
Cài đặt JobSet:
kubectl apply --server-side -f \
https://github.com/kubernetes-sigs/jobset/releases/download/v0.7.0/manifests.yaml
7.1 JobSet cho Distributed ML Training
Scenario: Train một model với kiến trúc Parameter Server — một nhóm pods làm parameter server (lưu trữ gradients), một nhóm khác làm workers (tính toán).
apiVersion: jobset.x-k8s.io/v1alpha2
kind: JobSet
metadata:
name: ml-training-pytorch
namespace: ml-training
annotations:
jobset.sigs.k8s.io/exclusive-topology: kubernetes.io/hostname
spec:
failurePolicy:
maxRestarts: 3 # Restart toàn bộ JobSet nếu có failure
replicatedJobs:
# Parameter Server: lưu model state, nhận gradients từ workers
- name: parameter-server
replicas: 1
template:
spec:
completions: 2
parallelism: 2
completionMode: Indexed
template:
spec:
containers:
- name: ps
image: pytorch/pytorch:2.2-cuda12.1-cudnn8-runtime
command: ["python", "train.py", "--role", "ps"]
env:
- name: ROLE
value: "parameter-server"
- name: JOB_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
resources:
requests:
cpu: "4"
memory: "16Gi"
restartPolicy: Never
# Workers: tính toán gradients, gửi lên PS
- name: worker
replicas: 1
template:
spec:
completions: 8 # 8 workers
parallelism: 8
completionMode: Indexed
template:
spec:
containers:
- name: worker
image: pytorch/pytorch:2.2-cuda12.1-cudnn8-runtime
command: ["python", "train.py", "--role", "worker"]
env:
- name: ROLE
value: "worker"
- name: PS_HOSTS
value: "ml-training-pytorch-parameter-server-0-0.ml-training-pytorch:8080,ml-training-pytorch-parameter-server-0-1.ml-training-pytorch:8080"
resources:
requests:
cpu: "4"
memory: "16Gi"
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
restartPolicy: Never
7.2 Tính Năng Nổi Bật của JobSet
- Failure policy propagation: Nếu một Job trong set fail, toàn bộ JobSet có thể restart hoặc fail cùng — không để Jobs "orphan"
- DNS-based communication: Các Jobs trong JobSet tự động có DNS records để giao tiếp với nhau (
{jobset-name}-{job-name}-{job-index}-{pod-index}.{jobset-name}) - Exclusive topology: Đảm bảo các Pods của cùng Job được schedule trên cùng rack/node (giảm network latency)
- Startup sequencing: Chỉ start worker sau khi PS đã sẵn sàng
7.3 Theo Dõi JobSet
# Xem trạng thái JobSet
kubectl get jobset -n ml-training
# Xem chi tiết
kubectl describe jobset ml-training-pytorch -n ml-training
# Xem logs của parameter server
kubectl logs -l jobset.sigs.k8s.io/job-name=parameter-server -n ml-training
# Xem logs của tất cả workers
kubectl logs -l jobset.sigs.k8s.io/job-name=worker -n ml-training --prefix
8. Tổng Kết: Khi Nào Dùng Gì?
- Job đơn giản: Một tác vụ, chạy một lần — dùng basic Job
- Parallel processing không cần order: NonIndexed Job với completions + parallelism
- Data partitioning: Indexed Job — mỗi Pod xử lý partition xác định
- Queue-based processing: Work queue Job + Redis/RabbitMQ
- Scheduled tasks: CronJob với timezone support
- Distributed training/HPC: JobSet cho multi-job coordination
Jobs và CronJobs là nền tảng của mọi batch processing system trên Kubernetes. Hiểu rõ các completion modes và failure policies giúp bạn xây dựng pipelines đáng tin cậy, đặc biệt với AI/ML workloads ngày càng phổ biến.