DaemonSets, Jobs and CronJobs
Three controllers beyond Deployments: DaemonSets run one Pod on each node, Jobs run work that finishes, and CronJobs run Jobs on a schedule.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- Write a DaemonSet from a Deployment skeleton, and decide whether it should tolerate the control-plane taint.
- Size a Job with completions, parallelism, backoffLimit and activeDeadlineSeconds, and confirm it from .status.succeeded.
- Schedule a CronJob with the right concurrencyPolicy and history limits, and start it by hand with kubectl create job --from.
A keeps a set number of running forever. That fits a web app, but not every kind of work. Kubernetes has a controller for each shape:
DaemonSet
one Pod on every node
Job
runs until the work is done
CronJob
starts a Job on a schedule
can generate Jobs and CronJobs, but not DaemonSets. So this lesson also shows the fastest way to write a DaemonSet by hand.
DaemonSets: one Pod per node
A DaemonSet runs one copy of its Pod on every node that its rules allow. When a node joins the cluster, the DaemonSet adds a Pod there. When a node leaves, its Pod goes too. That is how network agents, and log collectors end up on every node.
The normal places these Pods, so still apply:
- The has a NoSchedule taint. A DaemonSet adds a few by itself, but not one for this taint.
- So by default, a DaemonSet runs only on the worker nodes: 2 Pods on this lab.
- To cover every node, control plane included, write the control-plane toleration into the Pod template.
There is no kubectl create daemonset. Instead, generate a Deployment and turn it into a DaemonSet:
kubectl -n wl-batch create deployment node-agent --image=registry.k8s.io/pause:3.10 --dry-run=client -o yaml \
| sed -e 's/^kind: Deployment/kind: DaemonSet/' -e '/^ replicas:/d' -e '/^ strategy:/d' -e '/^status:/d' > ds.yaml
kubectl apply -f ds.yaml
kubectl -n wl-batch get ds node-agent # DESIRED CURRENT READY per eligible node
kubectl -n wl-batch get pods -l app=node-agent -o wideHere is a full DaemonSet. Keep the tolerations block to include the control plane, or remove it to stay on the workers:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
namespace: wl-batch
spec:
selector:
matchLabels:
app: log-agent
updateStrategy:
type: RollingUpdate # default, one node at a time; OnDelete waits for you to delete Pods
template:
metadata:
labels:
app: log-agent
spec:
tolerations: # remove this block to stay off the control plane
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
# nodeSelector: # or restrict to labeled nodes
# pool: logging
containers:
- name: agent
image: busybox:1.36
command: ["sh", "-c", "while true; do sleep 3600; done"]Jobs: run until enough Pods succeed
A Job runs Pods until a set number of them succeed, then stops. Example: a database migration for your Django app. It must run, finish, and not start again.
apiVersion: batch/v1
kind: Job
metadata:
name: resize-images
namespace: wl-batch
spec:
completions: 6 # successful Pods needed (default 1)
parallelism: 2 # Pods running at once (default 1)
backoffLimit: 3 # failed retries before the Job fails (default 6)
activeDeadlineSeconds: 300 # hard wall-clock limit, beats backoffLimit
ttlSecondsAfterFinished: 600 # delete the Job and its Pods 10 min after it ends
template:
spec:
restartPolicy: Never # Never or OnFailure; Always is rejected
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo resizing; sleep 3"]A Job's Pods must use restartPolicy: Never or OnFailure. The two differ in what happens after a failure:
- Either way, each retry counts toward
backoffLimit, and the wait between retries grows. - A Job ends with the condition
Complete, or withFailedand a reason:BackoffLimitExceededorDeadlineExceeded. - A Job's Pod template cannot be changed. To change a Job, delete it and create it again.
Create a Job, wait for it, then check it:
kubectl -n wl-batch create job once --image=busybox:1.36 -- sh -c 'echo done' # writes restartPolicy: Never
kubectl -n wl-batch create job once --image=busybox:1.36 --dry-run=client -o yaml -- sh -c 'echo done' > job.yaml # then add completions etc.
kubectl -n wl-batch wait --for=condition=complete job/once --timeout=120s
kubectl -n wl-batch get job once -o jsonpath='{.status.succeeded}/{.spec.completions}'; echo
kubectl -n wl-batch logs job/once
kubectl -n wl-batch get pods -l job-name=onceCronJobs: Jobs on a schedule
A CronJob creates a new Job each time its schedule comes round. Example: a report that your app emails every night at 02:30.
CronJob
holds the schedule
30 2 * * *
Job
one per run
Pod
does the work, then exits
Each level has its own spec, so the Pod template sits deep inside the CronJob: jobTemplate.spec.template.spec.
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
namespace: wl-batch
spec:
schedule: "30 2 * * *" # minute hour day-of-month month day-of-week
concurrencyPolicy: Forbid # Allow (default) | Forbid | Replace
successfulJobsHistoryLimit: 3 # default 3
failedJobsHistoryLimit: 1 # default 1
suspend: false
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: busybox:1.36
command: ["sh", "-c", "date; echo report done"]The schedule uses the five classic cron fields: minute, hour, day of month, month and day of week. Some common ones:
What if a run is due while the last one is still going? concurrencyPolicy decides:
To test a CronJob without waiting, run kubectl create job NAME --from=cronjob/CRON. It copies the job template and records the CronJob as the owner, so the history limits count it too.
Apps that need a fixed name and their own disk, such as a database, use a , taught in StatefulSets and volumeClaimTemplates.
In the official docs· open on exam day too
Run an agent on every worker node
wl-batch create a DaemonSet node-agent that runs exactly one Pod (image registry.k8s.io/pause:3.10, Pod label app=node-agent) on each worker node and none on the control plane. Each container requests 10m CPU and 16Mi memory.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-1/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-1/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-1/cleanup | bash
A Job that must succeed three times, one at a time
wl-batch create a Job process-items using image busybox:1.36 that runs sh -c 'echo processing; sleep 2'. The Job must finish after 3 successful Pods, run only one Pod at a time, retry a failure at most 2 times, never restart a failed container in place, and be stopped if it runs longer than 120 seconds. Wait until it has completed.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-2/cleanup | bash
Schedule a CronJob and run it once by hand
wl-batch create a CronJob heartbeat that runs every 5 minutes with image busybox:1.36 and command sh -c 'date; echo alive'. A new run must never start while the previous one is still running. Keep the last 2 successful Jobs and the last 1 failed Job. Then, without waiting for the schedule, start a Job named heartbeat-manual from this CronJob and make sure it succeeds.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-3/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-3/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/wl-batch-3/cleanup | bash
Finished this lesson?
0 of 3 tasks passed. Your readiness counts tasks, so run them before you move on.