Job vs CronJob

Key Differences in Kubernetes

A Job runs a task to completion — it creates one or more Pods and ensures they finish successfully. A CronJob creates Jobs on a recurring schedule defined by a cron expression. Use a Job for one-time tasks like database migrations; use a CronJob for recurring tasks like nightly backups or periodic cleanup.

Side-by-Side Comparison

DimensionJobCronJob
ExecutionRuns once when createdRuns on a recurring schedule defined by a cron expression
TriggerTriggered by creation of the Job resourceTriggered automatically by the CronJob controller at scheduled times
RelationshipStandalone resource or created by a CronJobHigher-level resource that creates and manages Jobs
Completion TrackingTracks completions and retries directlyDelegates completion tracking to the created Jobs
Concurrencyparallelism and completions control parallel executionconcurrencyPolicy controls whether concurrent Jobs are allowed
HistoryRemains until manually deleted or TTL expiresRetains configurable number of successful/failed Job history
Failure HandlingbackoffLimit controls retry attemptsInherits backoffLimit from Job template; also has startingDeadlineSeconds

Detailed Breakdown

Job — Run to Completion

A Job creates one or more Pods and ensures a specified number of them complete successfully. Unlike a Deployment (which keeps Pods running forever), a Job's Pods terminate once their task is done.

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
spec:
  backoffLimit: 3
  activeDeadlineSeconds: 600
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: migrate
          image: my-app:1.0.0
          command: ["python", "manage.py", "migrate"]
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: url

Key fields:

  • backoffLimit: 3 — retry up to 3 times on failure
  • activeDeadlineSeconds: 600 — kill the Job if it runs longer than 10 minutes
  • restartPolicy: Never — do not restart the container; create a new Pod instead (alternative: OnFailure to restart in-place)

Parallel Jobs

Jobs support parallel execution for batch workloads:

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-processor
spec:
  completions: 10
  parallelism: 3
  backoffLimit: 5
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: processor
          image: batch-worker:1.0.0

This runs 10 total completions with up to 3 Pods running in parallel at a time. Each Pod processes one unit of work. The Job is complete when 10 Pods have finished successfully.

CronJob — Scheduled Jobs

A CronJob creates Job objects on a cron schedule:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-backup
spec:
  schedule: "0 2 * * *"  # Every day at 2:00 AM
  timeZone: "America/New_York"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 300
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 3600
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: backup
              image: backup-tool:1.0.0
              command: ["./backup.sh"]
              env:
                - name: S3_BUCKET
                  value: "my-backups"

The cron schedule follows standard cron syntax: minute, hour, day-of-month, month, day-of-week. Common examples:

  • */5 * * * * — every 5 minutes
  • 0 */6 * * * — every 6 hours
  • 0 2 * * * — daily at 2 AM
  • 0 0 * * 0 — weekly on Sunday at midnight
  • 0 0 1 * * — first day of every month at midnight

Concurrency Policy

The concurrencyPolicy field is critical for CronJobs that might overlap:

spec:
  concurrencyPolicy: Allow    # Default — multiple Jobs can run at the same time
spec:
  concurrencyPolicy: Forbid   # Skip the new Job if the previous one is still running
spec:
  concurrencyPolicy: Replace  # Cancel the running Job and start a new one

For backups, Forbid is usually the right choice — you do not want two backup processes running concurrently. For idempotent tasks like sending reminders, Allow is fine. For data processing where only the latest run matters, Replace ensures you are always working on fresh data.

Job History Management

CronJobs create a new Job object on each schedule trigger. Without cleanup, these accumulate:

spec:
  successfulJobsHistoryLimit: 3   # Keep last 3 successful Jobs
  failedJobsHistoryLimit: 5       # Keep last 5 failed Jobs

Old Jobs (and their Pods) are automatically deleted. This prevents the namespace from filling up with completed Job objects.

For standalone Jobs (not created by a CronJob), you can use the TTL controller:

apiVersion: batch/v1
kind: Job
metadata:
  name: one-time-task
spec:
  ttlSecondsAfterFinished: 3600  # Delete Job 1 hour after completion
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: task
          image: task-runner:1.0.0

Missed Schedules and Deadlines

If the CronJob controller is down (or the cluster is unavailable) when a schedule fires, the Job is missed. The startingDeadlineSeconds field controls how late a Job can start:

spec:
  startingDeadlineSeconds: 300  # Allow up to 5 minutes late

If more than 100 schedules are missed within the startingDeadlineSeconds window, the CronJob stops trying and logs an error. This prevents a flood of Jobs when the controller recovers after extended downtime.

Monitoring and Debugging

# Check Job status
kubectl get jobs
kubectl describe job db-migration

# View Pods created by a Job
kubectl get pods --selector=job-name=db-migration

# Check CronJob schedule and last run
kubectl get cronjobs
kubectl describe cronjob nightly-backup

# View logs from the most recent Job Pod
kubectl logs job/db-migration

# Manually trigger a CronJob for testing
kubectl create job --from=cronjob/nightly-backup manual-backup-test

The kubectl create job --from=cronjob command is particularly useful for testing — it creates a one-off Job using the CronJob's template without waiting for the next scheduled run.

Failure Handling Strategies

For critical Jobs, combine multiple failure handling mechanisms:

apiVersion: batch/v1
kind: Job
spec:
  backoffLimit: 3              # Retry 3 times
  activeDeadlineSeconds: 1800  # Total time limit: 30 minutes
  template:
    spec:
      restartPolicy: OnFailure
      activeDeadlineSeconds: 600  # Per-Pod time limit: 10 minutes
      containers:
        - name: task
          image: critical-task:1.0.0
          livenessProbe:
            exec:
              command: ["cat", "/tmp/healthy"]
            periodSeconds: 30

This ensures the Job retries on failure, has a hard time limit, and the container is health-checked during execution.

Use Job when...

  • Running a one-time database migration or schema update
  • Processing a batch of data that needs to run to completion
  • Running integration tests or one-off scripts in the cluster
  • Performing a parallel computation with multiple completions

Use CronJob when...

  • Scheduling nightly database backups
  • Running periodic cleanup of expired data or temp files
  • Sending scheduled reports or notifications
  • Performing regular health checks or compliance scans
  • Rotating logs or certificates on a schedule

Model Interview Answer

A Job is a Kubernetes resource that runs a task to completion — it creates Pods, ensures they succeed, and retries on failure up to a backoffLimit. Once all Pods complete successfully, the Job is done. A CronJob builds on top of Jobs by creating them on a cron schedule, like running a backup every night at 2 AM. The CronJob manages history by keeping a configurable number of successful and failed Jobs. Key settings include concurrencyPolicy (Allow, Forbid, Replace) which controls what happens when the next schedule fires while a previous Job is still running, and startingDeadlineSeconds which sets how late a Job can start if it misses its window.

Related Comparisons