Job Parallelism and Completions
A single-completion Job processes one item. But what if you need to process 10 files, send 50 messages, or run a suite of integration tests? You could create 10 separate Jobs, but that is repetitive and hard to track. A single Job with completions: 10 and parallelism: 3 runs three Pods simultaneously, tracks how many have succeeded, and stops when 10 completions are recorded.
nano batch-job.yamlStart with the Job that requires multiple completions:
apiVersion: batch/v1kind: Jobmetadata: name: batch-jobspec: completions: 6 parallelism: 2 template: spec: restartPolicy: Never containers: - name: worker image: busybox:1.36 command: ['sh', '-c', 'echo Processing item && sleep 3']kubectl apply -f batch-job.yamlWhat completions and parallelism control
completions is the total number of successful Pod exits required before the Job is done. parallelism is the maximum number of Pods the Job controller will run simultaneously. The controller creates new Pods as previous ones complete, never exceeding parallelism, until completions is reached.
Watch the Pods as they run:
kubectl get pods -l job-name=batch-job --watchYou will see two Pods start, reach Completed, then two more start, until six total completions are recorded. Press Ctrl+C to exit the watch. Then check the Job:
kubectl get jobsCOMPLETIONS shows how many have succeeded out of the total required. DURATION shows the elapsed time since the Job started.
A Job has completions: 9 and parallelism: 3. How many waves of Pods will run, assuming no failures?
Reveal answer
3 waves. Each wave runs 3 Pods in parallel. 3 waves x 3 Pods = 9 completions. The Job finishes when all 9 Pods exit successfully.
Non-indexed vs indexed completion modes
By default, Jobs use non-indexed mode: each Pod is interchangeable and the Job simply counts successful exits. This works for processing items from a shared queue where each worker picks the next available item.
Kubernetes also supports completionMode: Indexed. Each Pod receives a unique index via the JOB_COMPLETION_INDEX environment variable (0 through completions-1). This lets each Pod know which specific item it is responsible for without an external queue.
nano indexed-job.yamlapiVersion: batch/v1kind: Jobmetadata: name: indexed-jobspec: completions: 4 parallelism: 2 completionMode: Indexed template: spec: restartPolicy: Never containers: - name: worker image: busybox:1.36 command: ['sh', '-c', 'echo "Processing index $JOB_COMPLETION_INDEX"']kubectl apply -f indexed-job.yamlkubectl get pods -l job-name=indexed-jobPod names for indexed Jobs include the index: indexed-job-0-<hash>, indexed-job-1-<hash>. Each Pod processes exactly one index.
kubectl logs -l job-name=indexed-jobEach Pod prints its own index. The four outputs together cover indices 0 through 3 with no overlap and no gap.
The default non-indexed mode is fine when workers pull from a shared queue and idempotency is guaranteed. If you use indexed mode, ensure your application actually uses JOB_COMPLETION_INDEX. A worker that ignores its index and processes the same default item on every run will appear to succeed while doing no useful work.
You have a dataset of 100 files, each identified by a number 0-99. Which Job configuration is most natural for processing them?
completions: 100, parallelism: 10, completionMode: Indexedcompletions: 100, parallelism: 10(non-indexed)completions: 1, parallelism: 100
Reveal answer
completionMode: Indexed with completions: 100. Each Pod receives a unique index matching a file number, so each Pod processes exactly one specific file. Non-indexed would work too if you have a queue, but indexed is more direct when items are identified by position. The third option runs 100 Pods but only waits for 1 completion, which is incorrect.
kubectl delete job batch-job indexed-jobParallelism and completions transform a Job from a one-shot task into a batch processing primitive. The next lesson covers what happens when Pods in a Job fail and how to configure retry limits and backoff behavior.