02 - Pods & Workload Controllers
Why this matters
The Pod is the atomic unit of scheduling. Everything else (Deployment, StatefulSet, DaemonSet, Job) is a controller that manages Pods for you in a specific pattern.
Read this first — Definitions & Explanations
Pod
The smallest deployable unit in Kubernetes. A Pod can hold one or more containers that share network namespace (same Pod IP / localhost) and can share volumes. You usually don’t keep “naked” Pods in production — controllers manage them.
Init containers
Run to completion before app containers start. Useful for setup: wait for a dependency, generate config, migrate something. If an init container fails, the Pod won’t proceed.
Sidecar containers
Extra containers that run alongside the main app in the same Pod (logging agent, proxy, sync helper). They share the Pod’s network and can share volumes.
ReplicaSet
Ensures a specified number of identical Pod replicas are running. You rarely create ReplicaSets by hand — Deployments own them.
Deployment
The standard controller for stateless apps. It manages ReplicaSets and gives you:
- desired replica count
- rolling updates
- rollbacks
When you change the image, Deployment creates a new ReplicaSet and shifts traffic gradually.
StatefulSet
For workloads that need stable identity and often stable storage per replica (databases, queues). Pods get ordered names (web-0, web-1) and stable network identities.
DaemonSet
Ensures a Pod runs on every node (or selected nodes): CNI agents, log shippers, node exporters, security agents.
Job / CronJob
- Job: run Pods until a task completes successfully (batch work).
- CronJob: schedule Jobs on a cron timetable.
Probes
- Liveness: “is this container alive?” Failure → kubelet restarts it.
- Readiness: “should it receive traffic?” Failure → removed from Service endpoints.
- Startup: gives slow apps time to boot before liveness checks start punishing them.
Rolling update knobs
maxSurge: how many extra Pods can exist during updatemaxUnavailable: how many Pods can be down during update
Official docs (read for detail)
- Pods
- Deployments
- StatefulSets
- DaemonSet
- Jobs / CronJob
- Configure Liveness, Readiness and Startup Probes
Key Concepts
- Pod = one or more containers sharing network namespace + storage
- Init containers vs sidecar containers
- ReplicaSet: keeps N replicas of a pod running (you rarely create these directly)
- Deployment: manages ReplicaSets, gives you rolling updates + rollbacks
- StatefulSet: stable network identity + stable storage per replica (databases, queues)
- DaemonSet: exactly one pod per node (log shippers, node exporters, CNI agents)
- Job / CronJob: run-to-completion workloads
- Pod lifecycle phases: Pending → Running → Succeeded/Failed
- Restart policies, liveness/readiness/startup probes
- Rolling update strategy:
maxSurge,maxUnavailable
YouTube search terms
- "Kubernetes Pods vs Deployments vs ReplicaSets explained"
- "Kubernetes StatefulSet vs Deployment"
- "Kubernetes liveness readiness startup probes explained"
- "Kubernetes Jobs and CronJobs tutorial"
Hands-on lab (on prod-sim)
# Deployment + rolling update + rollback
kubectl create deployment web --image=nginx:1.25 --replicas=3
kubectl rollout status deployment/web
kubectl set image deployment/web nginx=nginx:1.27
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
# Watch a StatefulSet get stable identities
kubectl apply -f https://k8s.io/examples/application/web/web.yaml
kubectl get pods -l app=nginx -o wide -w # note the ordered names: web-0, web-1, web-2
# DaemonSet: confirm one pod per node
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide # already a DaemonSet example
# Job / CronJob
kubectl create job hello --image=busybox -- echo "hello from a job"
kubectl create cronjob every-min --image=busybox --schedule="*/1 * * * *" -- echo "tick"
kubectl get jobs,cronjobs
# Break a probe on purpose and watch kubelet restart the container
kubectl run bad-probe --image=nginx --dry-run=client -o yaml > bad-probe.yaml
# edit bad-probe.yaml: add a livenessProbe httpGet path:/nonexistent port:80
kubectl apply -f bad-probe.yaml
kubectl get pod bad-probe -w # watch RESTARTS climb
kubectl describe pod bad-probe # read the Events section
Notes
(fill in your own words after watching + labbing)