Kodeloka
  1. Kodeloka
  2. Kelas Kubernetes
  3. Materi

8 · Pengelolaan · Modul 13 dari 14

Job, CronJob & DaemonSet

Beban kerja yang bukan layanan: tugas sekali jalan, tugas terjadwal, dan agen yang harus ada di setiap node.

Job: Sekali Jalan Sampai Selesai

apiVersion: batch/v1
kind: Job
metadata:
  name: migrasi-basisdata
spec:
  backoffLimit: 3            # coba ulang maksimal 3 kali
  activeDeadlineSeconds: 600 # batas waktu keseluruhan
  ttlSecondsAfterFinished: 3600   # hapus otomatis setelah 1 jam
  template:
    spec:
      restartPolicy: Never   # atau OnFailure — TIDAK BOLEH Always
      containers:
        - name: migrasi
          image: registry.contoh.com/pesanan:2.4.0
          command: ["./migrate", "up"]
⚠️ Jangan lupa ttlSecondsAfterFinished

Tanpa ini, setiap Job yang selesai beserta pod-nya tetap tersimpan selamanya di kluster. Sebuah CronJob yang berjalan tiap lima menit akan menumpuk ribuan objek dalam sebulan, membebani etcd dan membuat kubectl get pods tidak terbaca.

Job Paralel

spec:
  completions: 100      # total pekerjaan yang harus selesai
  parallelism: 10       # berapa yang berjalan bersamaan

# Atau mode indeks — tiap pod tahu nomor dirinya
  completionMode: Indexed
  # Tersedia sebagai variabel JOB_COMPLETION_INDEX

CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: laporan-harian
spec:
  schedule: "0 7 * * 1-5"          # 07:00 Senin–Jumat
  timeZone: "Asia/Jakarta"
  concurrencyPolicy: Forbid        # jangan tumpang tindih
  startingDeadlineSeconds: 300
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: laporan
              image: registry.contoh.com/laporan:1.2.0
concurrencyPolicyPerilaku bila jadwal tiba saat yang sebelumnya masih jalan
AllowJalankan bersamaan (bawaan) — sering menyebabkan masalah
ForbidLewati jadwal ini
ReplaceHentikan yang lama, mulai yang baru
🚫 concurrencyPolicy bawaan adalah Allow

Bila sebuah laporan biasanya selesai dalam 3 menit tetapi suatu hari melambat menjadi 20 menit, dengan jadwal tiap 5 menit Anda akan punya empat proses berjalan bersamaan — saling berebut database dan mungkin menghasilkan data ganda. Untuk hampir semua tugas terjadwal, Forbid adalah pilihan yang benar.

⚠️ CronJob memberi jaminan at-least-once, bukan exactly-once

Dalam keadaan tertentu — control plane sibuk, node bermasalah — sebuah jadwal bisa terlewat atau terjadi dua kali. Tugas terjadwal Anda harus idempoten. Jangan menulis tugas yang mengasumsikan ia berjalan tepat satu kali, terutama untuk hal seperti penagihan.

DaemonSet

Menjalankan tepat satu pod di setiap node — dipakai untuk agen infrastruktur.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: pengumpul-log
spec:
  selector:
    matchLabels: { app: pengumpul-log }
  template:
    metadata:
      labels: { app: pengumpul-log }
    spec:
      tolerations:
        - operator: Exists       # jalan di SEMUA node, termasuk yang ber-taint
      containers:
        - name: agen
          image: grafana/alloy:latest
          volumeMounts:
            - name: log-kontainer
              mountPath: /var/log/containers
              readOnly: true
      volumes:
        - name: log-kontainer
          hostPath:
            path: /var/log/containers

Kegunaan umum: pengumpul log (Alloy, Fluent Bit), eksportir metrik (node-exporter), plugin jaringan (Calico, Cilium), driver penyimpanan CSI, dan agen keamanan.

⚠️ Toleration untuk node control plane

Node control plane biasanya diberi taint agar beban kerja biasa tidak ditempatkan di sana. Bila agen pemantauan Anda perlu ikut memantau node tersebut, DaemonSet-nya harus punya toleration yang sesuai — kalau tidak, ada bagian kluster yang tidak terpantau tanpa Anda sadari.

Init Container

spec:
  initContainers:
    - name: tunggu-basisdata
      image: busybox:1.36
      command:
        - sh
        - -c
        - |
          until nc -z postgres 5432; do
            echo "menunggu basis data…"
            sleep 2
          done

    - name: jalankan-migrasi
      image: registry.contoh.com/pesanan:2.4.0
      command: ["./migrate", "up"]

  containers:
    - name: api
      image: registry.contoh.com/pesanan:2.4.0

Init container berjalan berurutan sampai selesai sebelum kontainer utama dimulai. Bila salah satu gagal, pod di-restart dan seluruh rangkaian diulang.

🚫 Migrasi database di init container itu berbahaya

Deployment dengan 3 replika berarti 3 pod menjalankan migrasi secara bersamaan. Sebagian alat migrasi punya penguncian dan akan aman; sebagian lagi akan merusak skema. Cara yang benar: jalankan migrasi sebagai Job terpisah sebelum rilis — atau, dalam Helm, sebagai pre-upgrade hook. Init container hanya tepat untuk menunggu kesiapan dependensi.

kubectl get jobs,cronjobs
kubectl get pods -l job-name=migrasi-basisdata
kubectl logs job/migrasi-basisdata
kubectl create job --from=cronjob/laporan-harian uji-manual
kubectl patch cronjob laporan-harian -p '{"spec":{"suspend":true}}'