Kubernetes Notes - Jobs, CronJob and Init Container
In Kubernetes, some workloads need to run continuously, such as web servers or APIs. These are typically managed by controllers like Deployments.
However, other workloads only need to run once and finish, such as scripts, data processing tasks, or backups. Kubernetes provides Jobs and CronJobs to handle these types of workloads.
Table of Contents
Job
A Job is a Kubernetes resource used to run a task until completion.
The Job controller creates a Pod that executes a command. Once the task finishes successfully, the Pod stops and the Job is marked as completed.
- Runs a task once
- Ensures the task completes successfully
- Creates one or more Pods to execute the task
- Stops once the task finishes
Create Job.
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: sleeper
5spec:
6 template:
7 spec:
8 restartPolicy: Never
9 containers:
10 - name: sleeper
11 image: debian
12 command: ["sleep", "15"]
Get the job.
1kubectl get job -n demo
2NAME STATUS COMPLETIONS DURATION AGE
3sleeper Running 0/1 12s 12s
Notice that job is not finish yet. After 15s the job completed.
1kubectl get job -n demo
2NAME STATUS COMPLETIONS DURATION AGE
3sleeper Complete 1/1 29s 71s
Cron
Sometimes tasks must run periodically, such as every hour or every day.
In traditional systems, this is handled using cron. Kubernetes provides the same functionality using CronJobs.
Create Cron.
schedule→ cron expression defining when the job runsjobTemplate→ specification of the Job to run
This cronjob will run every minute. Verify cronjob created.
1kubectl get cronjob -n demo
2NAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE
3sleeper */1 * * * * <none> False 1 7s 2m44s
Get the pods.
1kubectl get pods -n demo
2NAME READY STATUS RESTARTS AGE
3sleeper-29552118-sk9pc 0/1 Completed 0 2m11s
4sleeper-29552119-p88vr 0/1 Completed 0 71s
Notice that the pod is not READY, this a normal behavior - that means container has finished its job.
Init Container
You can create a container that performs task before your main container starts.
- Runs before any app container in the Pod
- Performs initialization tasks
- Must complete successfully before the main containers start
- Can run multiple init containers in sequence
Create Init Container
1apiVersion: v1
2kind: Pod
3metadata:
4 name: init-example
5spec:
6 initContainers:
7 - name: init-myservice
8 image: busybox
9 command: ['sh', '-c', 'echo "Initializing..." && sleep 5 && touch /data/ready']
10 volumeMounts:
11 - name: shared-data
12 mountPath: /data
13 containers:
14 - name: app
15 image: nginx
16 volumeMounts:
17 - name: shared-data
18 mountPath: /data
19 volumes:
20 - name: shared-data
21 emptyDir: {}
Get pods.
1kubectl get pods -n demo
2NAME READY STATUS RESTARTS AGE
3init-example 0/1 Init:0/1 0 4s
Check init container status.
1kubectl describe pod init-example -n demo
2Name: init-example
3Namespace: demo
4Priority: 0
5Service Account: default
6Node: master03/192.168.254.203
7Start Time: Tue, 10 Mar 2026 15:31:01 +0800
8Labels: <none>
9Annotations: cni.projectcalico.org/containerID: 36dbbac275093e3861699ea342852c340f231104e1fb0f0656d7900636c9a536
10 cni.projectcalico.org/podIP: 172.16.235.37/32
11 cni.projectcalico.org/podIPs: 172.16.235.37/32
12Status: Running
13IP: 172.16.235.37
14IPs:
15 IP: 172.16.235.37
16Init Containers:
17 init-myservice:
18 Container ID: containerd://46c42a97223d05df1ba36690ec82b23d03845c68ab1594d2c01064885d0ca7f5
19 Image: busybox
20 Image ID: docker.io/library/busybox@sha256:b3255e7dfbcd10cb367af0d409747d511aeb66dfac98cf30e97e87e4207dd76f
21 Port: <none>
22 Host Port: <none>
23 Command:
24 sh
25 -c
26 echo "Initializing..." && sleep 5 && touch /data/ready
27 State: Terminated
28 Reason: Completed
29 Exit Code: 0
30 Started: Tue, 10 Mar 2026 15:31:04 +0800
31 Finished: Tue, 10 Mar 2026 15:31:09 +0800
32 Ready: True
33 Restart Count: 0
34 Environment: <none>
35 Mounts:
36 /data from shared-data (rw)
37 /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-q8hzh (ro)
38Containers:
39 app:
40 Container ID: containerd://4b702cf75c30f1222e8ecb3dec202bae3c3dd3a6978d5a33f56b58fd80358a09
41 Image: nginx
42 Image ID: docker.io/library/nginx@sha256:0236ee02dcbce00b9bd83e0f5fbc51069e7e1161bd59d99885b3ae1734f3392e
43 Port: <none>
44 Host Port: <none>
45 State: Running
46 Started: Tue, 10 Mar 2026 15:31:11 +0800
47 Ready: True
48 Restart Count: 0
49 Environment: <none>
50 Mounts:
51 /data from shared-data (rw)
52 /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-q8hzh (ro)
53Conditions:
54 Type Status
55 PodReadyToStartContainers True
56 Initialized True
57 Ready True
58 ContainersReady True
59 PodScheduled True
60Volumes:
61 shared-data:
62 Type: EmptyDir (a temporary directory that shares a pod's lifetime)
63 Medium:
64 SizeLimit: <unset>
65 kube-api-access-q8hzh:
66 Type: Projected (a volume that contains injected data from multiple sources)
67 TokenExpirationSeconds: 3607
68 ConfigMapName: kube-root-ca.crt
69 Optional: false
70 DownwardAPI: true
71QoS Class: BestEffort
72Node-Selectors: <none>
73Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
74 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
75Events:
76 Type Reason Age From Message
77 ---- ------ ---- ---- -------
78 Normal Scheduled 48s default-scheduler Successfully assigned demo/init-example to master03
79 Normal Pulling 47s kubelet Pulling image "busybox"
80 Normal Pulled 46s kubelet Successfully pulled image "busybox" in 1.471s (1.471s including waiting). Image size: 2222260 bytes.
81 Normal Created 46s kubelet Created container: init-myservice
82 Normal Started 45s kubelet Started container init-myservice
83 Normal Pulling 40s kubelet Pulling image "nginx"
84 Normal Pulled 39s kubelet Successfully pulled image "nginx" in 1.565s (1.565s including waiting). Image size: 62944796 bytes.
85 Normal Created 38s kubelet Created container: app
86 Normal Started 38s kubelet Started container app