Files
rootnode-academy/content/root/root-06-kubernetes-application-workloads/m03-jobs-cronjobs-daemonsets/03-demonstration-job-lifecycle.md
T
ced4568andClaude Sonnet 5 7f6e1857c0 feat(curriculum): Phase 6C module upgrades, security assessment bank, ROOT 11 orientation
Upgrades six PARTIAL modules to the gold-module standard (lesson/demonstration/
knowledge-check/guided-exercise/lab(s)/reflection), preserving every existing lab
activity_id and scenario_id: root-06-m03 (jobs/cronjobs/daemonsets), root-07-m04
(ingress/networkpolicy), root-07-m02 (configuration/secrets, converted in place
from a bare 5-lab bank), root-09-m02 (serviceaccounts/rbac), root-09-m03
(network/supply-chain security), root-10-m03 (troubleshooting framework).

root-05-m01 (20-task kubectl-fluency bank) gets a minimal bookending lesson +
reflection rather than a full redesign, since each task already carries its own
explanation. root-12-m01, root-capstone-m01, and root-09-m04 are promoted to
READY via documented exceptions (no new activities) where adding one would
misrepresent their intentional design.

Wires a new rootnode-security-assessment (exam, 60min, hint_policy disabled)
using the existing Phase 3B assessment engine: 3 required hands-on CORE
scenarios + 4 random-draw pools covering SecurityContext, RBAC, network
policy, and the 7 previously-unwired CKS MCQs. Wires the previously-unwired
readiness-probe-task scenario as an OPTIONAL practice lab in root-10-m01,
using the existing is_required model.

Adds root-11-m01-devops-platform-thinking — an honest, lesson-only ROOT 11
orientation module naming DevOps/platform engineering practices already
exercised in ROOT 05-10/12, explicit that GitOps/CI-CD/IaC/observability need
lab infrastructure this platform doesn't yet provide. No fake labs.

Adds infra/scripts/validate-course-content.js: cross-checks the DB against
scenario/content files for duplicate ids, orphans, invalid references, cycles,
sequence collisions, instructor-notes leakage, and (new) self-paced content
deferring explanation to a live instructor. 0 errors against the resulting
22 courses/modules, 163 activities, 98 scenario files.

No application code changed — every gap was satisfiable with existing tables
(course_modules, module_activities, assessment_definitions) and the existing
content-delivery pipeline.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-26 11:20:17 -05:00

2.6 KiB

Demonstration: Watching a Job Actually Complete

Creating the Job

$ kubectl apply -f pi-job.yaml
job.batch/pi-job created

$ kubectl get jobs
NAME     COMPLETIONS   DURATION   AGE
pi-job   0/1           3s         3s

$ kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
pi-job-8x2kq     1/1     Running   0          3s

The Job's own status (0/1 completions) is tracked separately from its Pod's status — this matters because a Job can retry a FAILED Pod attempt without that looking like the healthy restart behavior you'd see on a Deployment.

Once the Pod's process actually exits successfully

$ kubectl get pods
NAME             READY   STATUS      RESTARTS   AGE
pi-job-8x2kq     0/1     Completed   0          8s

$ kubectl get jobs
NAME     COMPLETIONS   DURATION   AGE
pi-job   1/1           7s         8s

STATUS: Completed — not Running, not CrashLoopBackOff. This is the ONE status a long-running Deployment's Pod is never supposed to reach on its own; for a Job, it's success. The Job object itself now reports 1/1 and stops — nothing recreates this Pod, because "finished successfully" is the desired end state here, unlike a Deployment where exiting is always treated as something to fix.

What a FAILING Job attempt looks like, briefly

$ kubectl get pods
NAME              READY   STATUS   RESTARTS   AGE
bad-job-abc12     0/1     Error    0          5s
bad-job-def34     0/1     Error    0          2s

$ kubectl describe job bad-job
...
Events:
  Warning  BackoffLimitExceeded  Job has reached the specified backoff limit

Two DIFFERENT Pods (abc12, def34), not one Pod restarting twice — each failed attempt gets its own new Pod, up to backoffLimit. Once that limit is hit, the Job stops retrying and reports the failure via Events rather than trying forever.

Instructor Notes

Demo script: Run the successful case live; showing the FAILING case is optional if time is short, but the Completed vs Running/Error distinction is worth pausing on regardless.

Approximate timing: 8 minutes live; 5 minutes self-paced.

Common misconception to preempt: students who've only seen Deployments sometimes expect kubectl get pods to show the Job's Pod disappear once it's done. It doesn't, by default — it stays as Completed until manually cleaned up or a TTL is configured, which is worth mentioning briefly (not a hands-on topic here).

Optional extension: ask what kubectl get pods would show for a CronJob's Pods across several scheduled runs (answer: one Completed Pod per past run, accumulating — the same "nothing auto-cleans this up" behavior, multiplied by the schedule).