Home > Blog > tech

Kubernetes Jobs และ CronJobs คืออะไร? สอนรัน Batch Tasks บน K8s 2026

kubernetes jobs cronjobs guide
Kubernetes Jobs CronJobs Guide 2026
2026-04-16 | tech | 3500 words

ใน 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 QueuePods ดึงงานจาก 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หน้าที่
backoffLimit6จำนวนครั้งที่ Retry ถ้า Pod Fail
activeDeadlineSecondsไม่จำกัดเวลาสูงสุดที่ Job จะรัน (Timeout)
ttlSecondsAfterFinishedไม่ลบลบ Job อัตโนมัติหลังเสร็จ N วินาที
completions1จำนวน Pod ที่ต้องสำเร็จ
parallelism1จำนวน 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 CronJobApache AirflowArgo Workflows
ความซับซ้อนต่ำ (YAML)สูง (Python DAGs)ปานกลาง (YAML)
Dependenciesไม่รองรับรองรับ (DAG)รองรับ (DAG)
Retry Logicพื้นฐาน (backoffLimit)ยืดหยุ่นยืดหยุ่น
UI Dashboardไม่มี (ใช้ Lens/K9s)มี (Web UI)มี (Web UI)
Alertingต้องตั้ง Alert เองมีในตัวมีในตัว
เหมาะกับงานง่าย ๆ ที่ไม่มี DependenciesData 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 เป็น DefaultK8s 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
รันงานตาม ScheduleCronJob
รัน Parallel ProcessingJob + completions + parallelism
งานที่ต้อง TimeoutJob + activeDeadlineSeconds
งาน Pipeline ซับซ้อนArgo Workflows หรือ Airflow

Kubernetes Jobs และ CronJobs เป็น Workload Controllers ที่สำคัญสำหรับงาน Batch ทุกประเภท ตั้งแต่ Database Backup, Report Generation, Data Processing ไปจนถึง Cleanup Tasks ทำความเข้าใจ Parameters ที่สำคัญ เลือก concurrencyPolicy ที่เหมาะสม และอย่าลืม Monitor Jobs เพื่อให้มั่นใจว่างานสำเร็จทุกครั้ง


Back to Blog | iCafe Forex | SiamLanCard | Siam2R