ใน Kubernetes ไม่ใช่ทุก Workload ที่ต้อง "รันตลอดเวลา" หลายงานเป็นแบบ Run-to-completion (รันจนจบแล้วหยุด) เช่น Database Backup, Report Generation, Data Processing, Cleanup Tasks งานเหล่านี้ใช้ Job และ CronJob ใน Kubernetes
K8s Job — Run-to-Completion Workload
Job คืออะไร?
Job คือ Workload Controller ที่สร้าง Pod เพื่อรันงานจนเสร็จแล้วหยุด ต่างจาก Deployment ที่ต้องการให้ Pod รันตลอดเวลา Job ต้องการแค่ให้งานสำเร็จ ถ้า Pod ล้มเหลว Job จะสร้าง Pod ใหม่มารันแทน
Job Types
| Type | ลักษณะ | ตัวอย่าง |
| Non-Parallel (Default) | รัน 1 Pod, สำเร็จ 1 ครั้งก็จบ | Database Migration, Single Backup |
| Parallel with Fixed Count | รัน N Pods พร้อมกัน แต่ละตัวทำงานอิสระ | Batch Image Processing |
| Parallel with Work Queue | Pods ดึงงานจาก Queue ทำจนหมด | Message Queue Processing |
Job YAML พื้นฐาน
apiVersion: batch/v1
kind: Job
metadata:
name: db-backup
spec:
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["pg_dump"]
args: ["-h", "db-host", "-U", "admin", "-d", "mydb", "-f", "/backup/dump.sql"]
volumeMounts:
- name: backup-vol
mountPath: /backup
volumes:
- name: backup-vol
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: Never # สำคัญ! Job ใช้ Never หรือ OnFailure
backoffLimit: 3 # Retry สูงสุด 3 ครั้งถ้า Fail
Job Parameters สำคัญ
| Parameter | ค่า Default | หน้าที่ |
| backoffLimit | 6 | จำนวนครั้งที่ Retry ถ้า Pod Fail |
| activeDeadlineSeconds | ไม่จำกัด | เวลาสูงสุดที่ Job จะรัน (Timeout) |
| ttlSecondsAfterFinished | ไม่ลบ | ลบ Job อัตโนมัติหลังเสร็จ N วินาที |
| completions | 1 | จำนวน Pod ที่ต้องสำเร็จ |
| parallelism | 1 | จำนวน Pod ที่รันพร้อมกัน |
apiVersion: batch/v1
kind: Job
metadata:
name: batch-process
spec:
completions: 10 # ต้องสำเร็จ 10 Pods
parallelism: 3 # รัน 3 Pods พร้อมกัน
backoffLimit: 5 # Retry สูงสุด 5 ครั้ง
activeDeadlineSeconds: 3600 # Timeout 1 ชั่วโมง
ttlSecondsAfterFinished: 86400 # ลบหลัง 24 ชั่วโมง
template:
spec:
containers:
- name: processor
image: myapp/processor:v1
command: ["python", "process.py"]
restartPolicy: Never
CronJob — Scheduled Recurring Jobs
CronJob คืออะไร?
CronJob คือ Job ที่รันตาม Schedule (ตารางเวลา) เหมือน Crontab ใน Linux แต่ทำงานบน Kubernetes ใช้สำหรับงานที่ต้องทำซ้ำ ๆ เช่น Backup ทุกวัน, Report ทุกสัปดาห์, Cleanup ทุกชั่วโมง
Cron Expression
# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12)
# │ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
# │ │ │ │ │
# * * * * *
# ตัวอย่าง:
# "0 2 * * *" = ทุกวัน ตี 2
# "*/15 * * * *" = ทุก 15 นาที
# "0 0 * * 0" = ทุกวันอาทิตย์ เที่ยงคืน
# "0 6 1 * *" = วันที่ 1 ของทุกเดือน เวลา 06:00
# "0 */6 * * *" = ทุก 6 ชั่วโมง
# "30 8 * * 1-5" = วันจันทร์-ศุกร์ 08:30
CronJob YAML
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-db-backup
spec:
schedule: "0 2 * * *" # ทุกวัน ตี 2
concurrencyPolicy: Forbid # ไม่รัน Job ใหม่ถ้าตัวเก่ายังไม่เสร็จ
startingDeadlineSeconds: 300 # ถ้าเลยเวลา 5 นาที ไม่ต้องรัน
successfulJobsHistoryLimit: 3 # เก็บ Job สำเร็จล่าสุด 3 ตัว
failedJobsHistoryLimit: 3 # เก็บ Job ล้มเหลวล่าสุด 3 ตัว
suspend: false # true = หยุดชั่วคราว
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:16
command: ["/bin/sh", "-c"]
args:
- |
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME | \
gzip > /backup/db-$(date +%Y%m%d-%H%M%S).sql.gz
env:
- name: DB_HOST
value: "postgres-svc"
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_NAME
value: "production"
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
- name: backup-storage
mountPath: /backup
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure
concurrencyPolicy
| Policy | พฤติกรรม | เมื่อไรใช้ |
| Allow (Default) | อนุญาตให้ Job หลายตัวรันพร้อมกัน | งานที่ไม่ชนกัน เช่น ส่ง Email |
| Forbid | ไม่สร้าง Job ใหม่ถ้าตัวเก่ายังรันอยู่ | DB Backup (ไม่ควร Backup ซ้อน) |
| Replace | ลบ Job เก่าที่ยังรันอยู่ แล้วสร้างใหม่ | Report ที่ต้องการผลล่าสุดเสมอ |
ตัวอย่างจริง: Practical Examples
1. Database Backup (ทุกวัน)
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-backup
spec:
schedule: "0 3 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: mysql:8
command: ["/bin/sh", "-c"]
args:
- mysqldump -h mysql-svc -u root -p$MYSQL_ROOT_PASSWORD --all-databases |
gzip > /backup/mysql-$(date +%Y%m%d).sql.gz
envFrom:
- secretRef:
name: mysql-secrets
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure
2. Report Generation (ทุกสัปดาห์)
apiVersion: batch/v1
kind: CronJob
metadata:
name: weekly-report
spec:
schedule: "0 8 * * 1" # ทุกวันจันทร์ 08:00
jobTemplate:
spec:
template:
spec:
containers:
- name: report
image: myapp/report-generator:v2
command: ["python", "generate_report.py"]
args: ["--type", "weekly", "--send-email"]
envFrom:
- configMapRef:
name: report-config
restartPolicy: Never
backoffLimit: 2
3. Data Cleanup (ทุก 6 ชั่วโมง)
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-old-data
spec:
schedule: "0 */6 * * *"
jobTemplate:
spec:
ttlSecondsAfterFinished: 3600
template:
spec:
containers:
- name: cleanup
image: myapp/cleanup:v1
command: ["python", "cleanup.py"]
args: ["--older-than", "30d", "--dry-run=false"]
restartPolicy: Never
4. Batch Data Processing (One-time Job)
apiVersion: batch/v1
kind: Job
metadata:
name: process-csv-import
spec:
completions: 5 # 5 ไฟล์ต้อง Process
parallelism: 3 # รัน 3 ตัวพร้อมกัน
activeDeadlineSeconds: 7200 # Timeout 2 ชั่วโมง
template:
spec:
containers:
- name: processor
image: myapp/csv-processor:v1
command: ["python", "process_csv.py"]
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1"
restartPolicy: Never
Monitoring Jobs/CronJobs
# ดู Jobs ทั้งหมด
kubectl get jobs
kubectl get jobs -n my-namespace
# ดู CronJobs
kubectl get cronjobs
# ดูรายละเอียด Job
kubectl describe job db-backup
# ดู Pods ของ Job
kubectl get pods --selector=job-name=db-backup
# ดู Logs ของ Job Pod
kubectl logs job/db-backup
# ดูประวัติ CronJob
kubectl get jobs --selector=cronjob-name=daily-db-backup
# Trigger CronJob ด้วยตนเอง (รันทันทีไม่ต้องรอ Schedule)
kubectl create job --from=cronjob/daily-db-backup manual-backup-001
# หยุด CronJob ชั่วคราว
kubectl patch cronjob daily-db-backup -p '{"spec":{"suspend":true}}'
# เปิด CronJob กลับมา
kubectl patch cronjob daily-db-backup -p '{"spec":{"suspend":false}}'
Job vs External Scheduler
| เปรียบเทียบ | K8s CronJob | Apache Airflow | Argo Workflows |
| ความซับซ้อน | ต่ำ (YAML) | สูง (Python DAGs) | ปานกลาง (YAML) |
| Dependencies | ไม่รองรับ | รองรับ (DAG) | รองรับ (DAG) |
| Retry Logic | พื้นฐาน (backoffLimit) | ยืดหยุ่น | ยืดหยุ่น |
| UI Dashboard | ไม่มี (ใช้ Lens/K9s) | มี (Web UI) | มี (Web UI) |
| Alerting | ต้องตั้ง Alert เอง | มีในตัว | มีในตัว |
| เหมาะกับ | งานง่าย ๆ ที่ไม่มี Dependencies | Data Pipeline ซับซ้อน | CI/CD + Workflow ซับซ้อน |
แนวทาง: เริ่มด้วย K8s CronJob สำหรับงานง่าย ๆ ถ้าต้องการ Dependencies, Complex Retry, Dashboard ค่อยย้ายไปใช้ Airflow หรือ Argo Workflows
Common Pitfalls
| ปัญหา | สาเหตุ | วิธีแก้ |
| Job Pods ไม่ถูกลบ | ไม่ได้ตั้ง ttlSecondsAfterFinished | เพิ่ม ttlSecondsAfterFinished: 86400 |
| CronJob สร้าง Job ซ้อน | Job เก่ายังรันอยู่ | ใช้ concurrencyPolicy: Forbid |
| CronJob ไม่รัน | เลยเวลา startingDeadlineSeconds | เพิ่ม deadline หรือตรวจสอบ Schedule |
| Job Fail แต่ไม่ Alert | ไม่ได้ตั้ง Monitoring | ใช้ Prometheus + AlertManager ดู Job status |
| restartPolicy ผิด | ใช้ Always (ไม่รองรับใน Job) | ใช้ Never หรือ OnFailure |
| Timezone ผิด | K8s ใช้ UTC เป็น Default | K8s 1.27+ รองรับ timeZone field |
| Resource ไม่พอ | Job Pod ถูก OOMKilled | ตั้ง Resource Requests/Limits ให้เหมาะ |
ตั้ง Timezone (K8s 1.27+)
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-report
spec:
schedule: "0 8 * * *"
timeZone: "Asia/Bangkok" # ใช้เวลาไทย!
jobTemplate:
# ...
สรุป: เลือก Job Type ไหนดี?
| ต้องการ | ใช้ |
| รันงานครั้งเดียว | Job |
| รันงานตาม Schedule | CronJob |
| รัน Parallel Processing | Job + completions + parallelism |
| งานที่ต้อง Timeout | Job + activeDeadlineSeconds |
| งาน Pipeline ซับซ้อน | Argo Workflows หรือ Airflow |
Kubernetes Jobs และ CronJobs เป็น Workload Controllers ที่สำคัญสำหรับงาน Batch ทุกประเภท ตั้งแต่ Database Backup, Report Generation, Data Processing ไปจนถึง Cleanup Tasks ทำความเข้าใจ Parameters ที่สำคัญ เลือก concurrencyPolicy ที่เหมาะสม และอย่าลืม Monitor Jobs เพื่อให้มั่นใจว่างานสำเร็จทุกครั้ง