DaemonSets & Jobs/CronJobs

Kubernetes Intermediate/Advanced

Chapter 2 · DaemonSets & Jobs/CronJobs

Chapter 1 covered StatefulSets for identity/storage-sensitive workloads. This chapter covers two more specialized controllers, each genuinely different from anything covered so far: DaemonSets (one pod per node) and Jobs/CronJobs (run to completion, not forever).

DaemonSets — One Pod Per Node, Guaranteed

A DaemonSet ensures exactly one copy of a pod runs on every node in the cluster (or a selected subset via node selectors) — genuinely different from a Deployment's "N replicas, scheduler decides where" model. A DaemonSet's desired count is inherently tied to the number of nodes, not an arbitrary number you specify. When a new node joins the cluster, the DaemonSet automatically schedules a pod there too — another instance of Chapter 2 (Course 1)'s reconciliation loop, just with desired state defined as "one per node" rather than a fixed number.

What DaemonSets Are Actually Used For

  • Log collection agents (e.g. Fluentd/Fluent Bit) — needs to run on every node to collect logs from that node's own containers (k8s2-7's upcoming observability chapter builds on this).
  • Monitoring/metrics agents (e.g. Prometheus's node-exporter) — needs per-node system-level metrics, also feeding into k8s2-7.
  • Networking/CNI plugin pods — some cluster networking implementations run as DaemonSets themselves, tying back to k8s1-2's own architecture material.

The common thread: infrastructure-level concerns that are inherently per-node, not per-application.

A Concrete DaemonSet YAML, Explained

apiVersion: apps/v1 kind: DaemonSet metadata: name: log-agent spec: selector: matchLabels: app: log-agent template: metadata: labels: app: log-agent spec: containers: - name: fluent-bit image: fluent/fluent-bit:latest

Same apps/v1 group as Deployment/StatefulSet — Chapter 1's own "sibling controller" point holds again. Critically: no replicas field at all, since the count is implicitly "one per matching node," not something specified directly.

Jobs — Run to Completion, Not Forever

A completely different category: Deployments, StatefulSets, and DaemonSets are all about keeping something running indefinitely. A Job is for a task that should run once (or a specified number of times) and then stop — directly tying back to k8s1-3's own Pod lifecycle material (Succeeded/Failed terminal states) and k8s1-11's OnFailure restart policy, which exists specifically for this use case. Genuinely common real uses: a database migration script, a one-off batch data-processing task, sending a batch of emails.

Job Completion & Parallelism

spec.completions — how many successful pod completions are needed for the Job to be considered done. spec.parallelism — how many pods can run at once working toward that count. A Job processing 100 queue items could run completions: 100, parallelism: 10, processing 10 items concurrently until all 100 finish — a genuinely different kind of "scaling" concept from Course 2's own upcoming k8s2-6 autoscaling material, worth not conflating.

CronJobs — Scheduled Jobs

A CronJob is, in a sense, to a Job what a Deployment is to a Pod — it creates Jobs on a recurring schedule, using standard cron syntax. Genuinely common real uses: nightly database backups, periodic cleanup tasks, scheduled report generation. Each scheduled run creates a new Job object, which then creates pods per that Job's own completion/parallelism settings — worth being explicit about the layering: CronJob creates Jobs, Jobs create Pods, three distinct layers.

A Concrete CronJob YAML, Explained

apiVersion: batch/v1 kind: CronJob metadata: name: nightly-backup spec: schedule: "0 2 * * *" # 2am daily, standard cron syntax jobTemplate: spec: template: spec: containers: - name: backup image: backup-tool:latest restartPolicy: OnFailure

Yet another distinct API group — batch/v1 — reinforcing the recurring "apiVersion differs by kind" lesson from Chapters 5, 6, and 9. Note the genuinely deep nesting: spec.jobTemplate.spec.template.spec — a CronJob spec containing a Job spec containing a pod spec, three layers deep, worth reading carefully rather than being intimidated by.

CronJob → Job → Pod, three layers
Keeping this chain straight matters directly for troubleshooting later (k8s2-8): a failed backup could mean the CronJob never triggered, the Job it created failed, or the Pod that Job spawned crashed — three genuinely different places to look.

A Genuinely Common Gotcha — Missed & Overlapping Schedules

What happens if a CronJob's previous run is still executing when the next scheduled time arrives? spec.concurrencyPolicy controls this: Allow (default, runs can overlap), Forbid (skip the new run if the previous is still going), Replace (cancel the old run, start the new one). Genuinely important to configure deliberately for something like a database backup — overlapping backup runs could cause real problems.

Leaving concurrencyPolicy at its default for a backup job is a real risk
The default, Allow, permits overlapping runs — for a job that genuinely shouldn't run twice concurrently (a backup writing to the same target, for instance), this can cause real data corruption or resource contention. Set Forbid explicitly for anything where overlap would be a genuine problem, rather than leaving the default unexamined.

Hands-On Exercises

Exercise 1

Explain why a DaemonSet's "desired pod count" isn't something you directly specify the way a Deployment's replica count is, and give one concrete real-world example of a workload that genuinely needs to run on every node.

📄 View solution
Exercise 2

Explain the three-layer relationship between a CronJob, a Job, and a Pod — which one creates which.

📄 View solution
Exercise 3

A team runs a nightly database backup as a CronJob with the default concurrencyPolicy. One night the backup takes much longer than usual and is still running when the next scheduled run begins. Explain what happens by default, why this could be a real problem for a backup job specifically, and what concurrencyPolicy setting would prevent it.

📄 View solution

Chapter 2 Quick Reference

  • DaemonSet — one pod per node, automatically, no replicas field; used for log/metrics agents and CNI plugins
  • Job — runs to completion, not forever; completions/parallelism control how much work and how much concurrency
  • CronJob — creates Jobs on a schedule; three layers: CronJob → Job → Pod
  • CronJob uses yet another apiVersion (batch/v1) — the recurring apiVersion-differs-by-kind pattern continues
  • concurrencyPolicy (Allow/Forbid/Replace) — leaving it at the default Allow for something like a backup risks real overlap problems
  • Next chapter: Helm — Package Management for Kubernetes — charts, templating, releases