So why bother creating a Job to run a Pod only once instead of using bare Pods? Using Jobs provides many reliability and scalability benefits that make them the pre‐ ferred option: 

• A Job is not an ephemeral in-memory task, but a persisted one that survives clus‐ ter restarts. 

• When a Job is completed, it is not deleted but kept for tracking purposes. The Pods that are created as part of the Job are also not deleted but available for examination (e.g., to check the container logs). This is also true for bare Pods, but only for a restartPolicy: OnFailure . 

• A Job may need to be performed multiple times. Using the .spec.completions field it is possible to specify how many times a Pod should complete successfully before the Job itself is done. 

• When a Job has to be completed multiple times (set through .spec.comple tions ), it can also be scaled and executed by starting multiple Pods at the same time. That can be done by specifying the .spec.parallelism  field. 

• If the node fails or when the Pod is evicted for some reason while still running, the scheduler places the Pod on a new healthy node and reruns it. Bare Pods would remain in a failed state as existing Pods are never moved to other nodes. 

All of this makes the Job primitive attractive for scenarios where some guarantees are required for the completion of a unit of work. 

The two fields that play major roles in the behavior of a Job are: 

.spec.completions 

Specifies how many Pods should run to complete a Job. 

.spec.parallelism 

Specifies how many Pod replicas could run in parallel. Setting a high number does not guarantee a high level of parallelism and the actual number of Pods may still be less (and in some corner cases, more) than the desired number (e.g., due to throttling, resource quotas, not enough completions left, and other reasons). Setting this field to 0 effectively pauses the Job. 

Figure 7-1 shows how the Batch Job  defined in Example 7-1 with a completion count of five and a parallelism of two is processed. 

