Kubernetes Workloads
Deployment, ReplicaSet, StatefulSet and DaemonSet, Jobs and CronJobs, rolling updates and rollback, and the HPA and autoscaling family.
12 questions
JuniorTheoryVery commonWhat is a Deployment in Kubernetes, and how does it relate to a ReplicaSet and to Pods?
What is a Deployment in Kubernetes, and how does it relate to a ReplicaSet and to Pods?
A Deployment is a controller for stateless apps: it declares a desired image and replica count. It manages a ReplicaSet, which keeps that many identical Pods running — the Pods are the containers. On an update it creates a new ReplicaSet and shifts Pods over, so you edit the Deployment, not the Pods directly.
Common mistakes
- ✗Thinking a Deployment is a Pod rather than a controller over ReplicaSets
- ✗Editing Pods directly instead of the Deployment's spec
- ✗Believing the Deployment talks to Pods with no ReplicaSet in between
Follow-up questions
- →What happens to the old ReplicaSet after a successful rolling update?
- →Why does scaling a Deployment change replicas without creating a new ReplicaSet?
JuniorTheoryCommonWhat is the difference between a Job and a CronJob, and when do you use each?
What is the difference between a Job and a CronJob, and when do you use each?
A Job runs a Pod to completion — it retries until a set number of successful runs finish, then stops; it fits one-off batch work like a data migration. A CronJob is a scheduler that creates a new Job on a cron schedule, for recurring work like nightly backups. So a CronJob is essentially a Job factory driven by time.
Common mistakes
- ✗Swapping the roles — thinking the Job carries the schedule
- ✗Expecting a Job to run forever like a Deployment instead of completing
- ✗Believing a CronJob runs the work itself rather than creating Jobs
Follow-up questions
- →What do a Job's
completionsandparallelismfields control? - →Why can a CronJob miss or overlap runs, and how do you guard against it?
JuniorCodeCommonComplete a minimal Deployment manifest for an app with 3 replicas and a container port.
Complete a minimal Deployment manifest for an app with 3 replicas and a container port.
Set spec.replicas: 3 and add ports under the container with containerPort: 8080. The selector.matchLabels must match template.metadata.labels (app: web), or the Deployment adopts no Pods and the apply is rejected. apiVersion is apps/v1, kind is Deployment; the template is the Pod spec the ReplicaSet stamps out three times.
Common mistakes
- ✗Selector labels not matching the template labels, so no Pods are managed
- ✗Putting
containerPortorreplicasat the wrong nesting level - ✗Using
kind: Pod/apiVersion: v1instead ofDeployment/apps/v1
Follow-up questions
- →What does the API reject at apply time if the selector does not match the template labels?
- →Why is
containerPortinformational rather than what actually exposes the app?
MiddleTheoryCommonWhat does the HorizontalPodAutoscaler (HPA) scale on, and what must be in place for it to work?
What does the HorizontalPodAutoscaler (HPA) scale on, and what must be in place for it to work?
The HPA changes a Deployment's replica count to hit a target metric — typically average CPU. It needs a metrics-server (or custom-metrics adapter) feeding live usage, and Pods must declare resource requests so a percentage target has a base. It scales within minReplicas/maxReplicas and does not resize Pods.
Common mistakes
- ✗Confusing the HPA (replica count) with the VPA (per-Pod requests)
- ✗Forgetting the metrics-server and requests prerequisites for a % target
- ✗Thinking the HPA scales nodes rather than Pods
Follow-up questions
- →Why does a CPU-percentage target silently break if Pods declare no requests?
- →How does the HPA combine several metrics into one desired replica count?
MiddleTheoryCommonHow do you roll back a bad Deployment, and what does kubectl rollout undo actually do?
How do you roll back a bad Deployment, and what does kubectl rollout undo actually do?
kubectl rollout undo deploy/x reverts to the previous revision. Kubernetes keeps old ReplicaSets (bounded by revisionHistoryLimit), so it scales the prior ReplicaSet back up — itself a rolling update. Add --to-revision=N for a specific one; rollout history lists them. It does not delete the Deployment or touch your data.
Common mistakes
- ✗Thinking undo deletes and recreates the Deployment from a saved file
- ✗Believing a rollback reverts data or volumes, not just the Pod template
- ✗Assuming only one revision is kept, so
--to-revisionis unavailable
Follow-up questions
- →How does
revisionHistoryLimitaffect which revisions you can roll back to? - →Why is a rollback itself governed by the same rolling-update strategy?
MiddleTheoryCommonHow does a rolling update work, and what do maxSurge and maxUnavailable control?
How does a rolling update work, and what do maxSurge and maxUnavailable control?
A rolling update replaces Pods gradually — the Deployment brings up new-version Pods and retires old ones a few at a time, so the app stays available. maxSurge caps how many Pods above the desired count may exist during the roll; maxUnavailable caps how many below it may be missing. New Pods must pass readiness to proceed.
Common mistakes
- ✗Thinking a rolling update deletes all old Pods before creating new ones
- ✗Confusing
maxSurge/maxUnavailablewith traffic-splitting knobs - ✗Forgetting that readiness gates each step of the roll
Follow-up questions
- →How do maxSurge: 0 and maxUnavailable: 0 interact, and why is that config invalid?
- →Why does a failing readiness probe stall a rolling update?
MiddleTheoryCommonWhen do you use a StatefulSet instead of a Deployment, and what guarantees does it add?
When do you use a StatefulSet instead of a Deployment, and what guarantees does it add?
Use a StatefulSet for stateful apps needing a stable identity — databases, clustered stores. Unlike a Deployment's interchangeable Pods, each Pod gets a stable ordinal name and DNS hostname, a sticky PersistentVolumeClaim that survives rescheduling, and ordered, one-at-a-time create/scale/update. A Deployment fits stateless, swappable replicas.
Common mistakes
- ✗Thinking a StatefulSet is only a Deployment under a different name
- ✗Expecting Pods to share one PVC rather than each keeping a sticky one
- ✗Missing the ordered, one-at-a-time create, scale and update behaviour
Follow-up questions
- →How does a StatefulSet's headless Service give each Pod a stable DNS name?
- →What happens to a StatefulSet Pod's PVC when the Pod is rescheduled?
MiddleTheoryOccasionalWhat is a DaemonSet, and give two real use cases where it is the right fit.
What is a DaemonSet, and give two real use cases where it is the right fit.
A DaemonSet runs exactly one Pod of its kind on every node (or every node matching a selector) and automatically adds a Pod when a new node joins. Unlike a Deployment you set no replica count — node count decides it. Typical uses: a per-node log collector like Fluent Bit and a monitoring agent like node-exporter.
Common mistakes
- ✗Setting a replica count on a DaemonSet instead of letting node count drive it
- ✗Thinking it schedules Pods anywhere rather than one per node
- ✗Forgetting it auto-adds a Pod when a new node joins
Follow-up questions
- →How do tolerations let a DaemonSet run on tainted control-plane nodes?
- →How does a DaemonSet roll out an update across its Pods on every node?
MiddleDebuggingOccasionalA rolling update is stuck at 2 of 5 updated replicas and new Pods never go Ready — diagnose it.
A rolling update is stuck at 2 of 5 updated replicas and new Pods never go Ready — diagnose it.
The new Pods are Running but 0/1 Ready because their readiness probe returns 503, so the Deployment won't retire more old Pods — maxUnavailable bounds the roll and it stalls. Fix the real readiness cause (a dependency, wrong path/port, or short delay), not the replica count. If the app is only slow to warm up, add a startupProbe.
Common mistakes
- ✗Raising replicas or resources instead of fixing the readiness failure
- ✗Deleting the readiness probe to force the roll to finish
- ✗Confusing a failing readiness probe with an image-pull error
Follow-up questions
- →When is the right fix a
startupProbeversus a longerinitialDelaySeconds? - →How does
maxUnavailable: 0change the behaviour of this stalled roll?
SeniorDebuggingOccasionalAn HPA shows TARGETS <unknown>/80% and never scales — diagnose the missing metrics path.
An HPA shows TARGETS <unknown>/80% and never scales — diagnose the missing metrics path.
<unknown> means the HPA cannot read the metric, so it computes no desired replica count. kubectl top failing points at the root: no metrics-server, so the resource-metrics API returns nothing. Repair the metrics-server, and confirm Pods declare CPU requests — a CPU% target needs a base. It is not a threshold or min/max issue.
Common mistakes
- ✗Lowering the target percentage instead of restoring the metrics pipeline
- ✗Ignoring that a failing
kubectl topsignals a missing metrics-server - ✗Forgetting that a CPU% target needs Pod requests to compute
Follow-up questions
- →Why does a CPU-percentage HPA need the Pods to declare CPU requests?
- →How would you tell a metrics-server outage from a missing custom-metrics adapter?
SeniorTheoryOccasionalCompare horizontal, vertical and cluster autoscaling — what does each scale, and when do they conflict?
Compare horizontal, vertical and cluster autoscaling — what does each scale, and when do they conflict?
The HorizontalPodAutoscaler (HPA) scales replica count on load; the VerticalPodAutoscaler (VPA) resizes a Pod's requests; the Cluster Autoscaler adds or removes nodes for unschedulable Pods or idle capacity. HPA and VPA clash on the same CPU metric — a VPA raising requests fights an HPA on CPU% — so combine VPA with HPA only on custom metrics.
Common mistakes
- ✗Mixing up which one scales replicas, requests, or nodes
- ✗Running the VPA and the HPA on the same CPU metric so they fight
- ✗Assuming the Cluster Autoscaler resizes Pods rather than node count
Follow-up questions
- →Why can the Cluster Autoscaler add nodes but fail to remove them?
- →How do you safely combine the VPA and the HPA on one workload?
SeniorCodeRareA CronJob's runs overlap and pile up — fix it with concurrencyPolicy and history limits.
A CronJob's runs overlap and pile up — fix it with concurrencyPolicy and history limits.
Set concurrencyPolicy: Forbid so a new run is skipped while the previous Job still runs (or Replace to cancel the old). Cap retained history with successfulJobsHistoryLimit and failedJobsHistoryLimit (e.g. 3 and 1); startingDeadlineSeconds skips long-missed ticks. Forbid stops the pile-up; the limits stop old Jobs cluttering the namespace.
Common mistakes
- ✗Thinking
concurrencyPolicy: Allowprevents overlap (it permits it) - ✗Confusing history limits with retry or parallelism settings
- ✗Using
suspend(which stops all runs) to fix overlap
Follow-up questions
- →How do
ForbidandReplacediffer when a run is still in flight? - →What does
startingDeadlineSecondsdo when the controller misses a schedule?