Kubernetes Jobs and CronJobs for batch workloads

Ryan Nakamura Feb 2026
1 tab
# === One-off Job: Database migration ===
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
  namespace: production
spec:
  ttlSecondsAfterFinished: 3600    # Auto-cleanup after 1 hour
  backoffLimit: 3                   # Retry up to 3 times on failure
  activeDeadlineSeconds: 600        # Timeout after 10 minutes
  template:
    metadata:
      labels:
        app: db-migrate
    spec:
      restartPolicy: Never           # Don't restart — let Job controller handle retries
      serviceAccountName: migration-runner
      containers:
        - name: migrate
          image: myapp:latest
          command: ["rails", "db:migrate"]
          envFrom:
            - secretRef:
                name: database-credentials
          resources:
            requests:
              cpu: 250m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 1Gi
---
# === Parallel Job: Process items in batch ===
apiVersion: batch/v1
kind: Job
metadata:
  name: batch-processor
  namespace: production
spec:
  completions: 10           # Total items to process
  parallelism: 3            # Run 3 pods at a time
  backoffLimit: 5
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: processor
          image: myapp-worker:latest
          command: ["python", "process_batch.py"]
          env:
            - name: BATCH_SIZE
              value: "100"
            - name: JOB_COMPLETION_INDEX
              valueFrom:
                fieldRef:
                  fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
---
# === CronJob: Nightly database backup ===
apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-backup
  namespace: production
spec:
  schedule: "0 2 * * *"              # Daily at 2:00 AM UTC
  timeZone: "America/New_York"        # K8s 1.27+
  concurrencyPolicy: Forbid           # Don't run if previous is still running
  successfulJobsHistoryLimit: 7       # Keep last 7 successful runs
  failedJobsHistoryLimit: 3           # Keep last 3 failed runs
  startingDeadlineSeconds: 300        # Skip if missed by > 5 min
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 86400
      backoffLimit: 2
      template:
        spec:
          restartPolicy: OnFailure
          volumes:
            - name: backup-storage
              persistentVolumeClaim:
                claimName: backup-pvc
          containers:
            - name: backup
              image: postgres:16-alpine
              command:
                - /bin/sh
                - -c
                - |
                  TIMESTAMP=$(date +%Y%m%d-%H%M%S)
                  FILENAME="backup-${TIMESTAMP}.sql.gz"
                  echo "Starting backup: ${FILENAME}"
                  pg_dump "$DATABASE_URL" | gzip > "/backups/${FILENAME}"
                  echo "Backup complete: $(ls -lh /backups/${FILENAME})"
                  # Prune backups older than 30 days
                  find /backups -name "backup-*.sql.gz" -mtime +30 -delete
              envFrom:
                - secretRef:
                    name: database-credentials
              volumeMounts:
                - name: backup-storage
                  mountPath: /backups
              resources:
                requests:
                  cpu: 250m
                  memory: 512Mi
                limits:
                  cpu: "1"
                  memory: 2Gi
---
# === CronJob: Cache warm-up every 5 minutes ===
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cache-warmer
  namespace: production
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Replace          # Kill old one if new one starts
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      ttlSecondsAfterFinished: 300
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: warmer
              image: curlimages/curl:latest
              command:
                - /bin/sh
                - -c
                - |
                  for endpoint in /api/popular /api/categories /api/featured; do
                    STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://api-service:3000${endpoint}")
                    echo "Warmed ${endpoint}: HTTP ${STATUS}"
                  done
1 file · yaml Explain with highlit

Run one-off tasks and scheduled batch processing in Kubernetes with Job and CronJob resources. Configure parallelism, backoff limits, completion counts, and cron schedules. Handle cleanup policies and monitor job history for reliable batch operations.