Kubernetes Workloads
Pods, controllers, probes, autoscaling, and resource management.
What is a Pod and why is it the smallest deployable unit?
A Pod wraps one or more containers that share network namespace (one IP, shared localhost) and can share volumes. Kubernetes schedules and manages at the Pod level, not individual containers. Multi-container Pods are used for sidecars (logging, proxy, config reload) or tightly coupled processes. Pods are ephemeral - they are created, destroyed, and replaced; you rarely manage bare Pods directly in production.
What is a ReplicaSet and how does it differ from a Deployment?
A ReplicaSet ensures a specified number of identical Pod replicas are running. If a Pod is deleted or a node fails, it creates replacements. Deployments own ReplicaSets and add rollout semantics: rolling updates, rollback to previous ReplicaSets, and pause/resume. You almost always use Deployments in production; ReplicaSets are the mechanism Deployments use under the hood, not something you create manually for stateless apps.
How do Deployments handle rolling updates and rollbacks?
A Deployment update creates a new ReplicaSet with the new Pod template and gradually scales it up while scaling the old ReplicaSet down (maxSurge, maxUnavailable control the pace). Kubernetes keeps old ReplicaSets for rollback history (revisionHistoryLimit). kubectl rollout undo reverts to a previous ReplicaSet. Readiness probes ensure new Pods receive traffic only when ready, preventing downtime during rollouts.
When should you use a StatefulSet instead of a Deployment?
StatefulSets are for workloads needing stable network identity and persistent storage per replica: databases (PostgreSQL, MongoDB), Kafka, ZooKeeper. Each Pod gets a predictable name (app-0, app-1), ordered startup/termination, and its own PersistentVolumeClaim. Deployments give random Pod names and interchangeable replicas - fine for stateless APIs, wrong for clustered databases that care about identity and data locality.
What is a DaemonSet and when is it used?
A DaemonSet ensures one Pod copy runs on every node (or every node matching a selector). Use cases: log collectors (Fluent Bit), monitoring agents (node-exporter), CNI plugins, or security scanners. When you add a node, the DaemonSet scheduler places its Pod automatically; when a node is removed, the Pod is garbage-collected. Unlike Deployments, you scale by adding nodes, not by changing replica count.
How do Jobs and CronJobs differ from long-running workloads?
Jobs run Pods until they complete successfully a set number of times (completions, parallelism). Use them for batch processing, migrations, or one-off tasks. CronJobs wrap Jobs on a schedule (like cron). They are not restarted on failure indefinitely unless restartPolicy and backoff limits allow retries. Long-running Deployments keep Pods running forever; Jobs exit when work is done.
Explain liveness, readiness, and startup probes.
- Liveness - "Is the container alive?" Fails → kubelet restarts the container. Use when the app can deadlock but the process still runs.
- Readiness - "Can this Pod receive traffic?" Fails → Pod is removed from Service endpoints but not restarted. Use when the app depends on DB warmup or external deps.
- Startup - Disables liveness/readiness until the app finishes slow startup (e.g. loading large models). Prevents liveness killing a still-booting container.
How does the Horizontal Pod Autoscaler (HPA) work?
HPA watches metrics (usually CPU/memory via metrics-server, or custom metrics from Prometheus) and scales a Deployment/StatefulSet replica count up or down to match a target (e.g. 70% CPU utilization). It runs in the control plane, evaluates every few seconds, and respects minReplicas/maxReplicas. HPA needs resource requests set on containers for CPU-based scaling; without requests, it cannot compute utilization percentage.
What is the difference between resource requests and limits?
Requests are guaranteed resources the scheduler uses for placement - a Pod is scheduled only onto nodes with enough allocatable CPU/memory after requests. Limits cap maximum usage; exceeding CPU limits throttles the container, exceeding memory limits triggers OOMKill. Best practice: set requests close to steady-state usage, limits higher for burst (or equal for predictable workloads). Missing requests cause poor scheduling and broken HPA.
What happens when a Pod exceeds its memory limit?
The Linux kernel OOM killer terminates the container process. Kubernetes may restart it per restartPolicy. Repeated OOMKills indicate limits are too low or a memory leak. Unlike CPU (which is compressible/throttled), memory is not - there is no graceful slowdown. Monitor OOM events and set limits based on profiling; consider Vertical Pod Autoscaler (VPA) for recommendation-only or automatic request/limit tuning.
What are init containers and when would you use them?
Init containers run sequentially before app containers start, and must all succeed. Use them to wait for dependencies (DB ready), download config/artifacts, run migrations, or set permissions on volumes. They share volumes with app containers but not the same image lifecycle. Example: an init container runs flyway migrate before the API server container starts serving traffic.
How do you choose the right workload type for a given application?
- Deployment - stateless web APIs, microservices, anything horizontally scalable with interchangeable replicas.
- StatefulSet - databases, queues, or apps needing stable hostname and per-replica disk.
- DaemonSet - per-node agents (logs, metrics, security).
- Job / CronJob - batch ETL, backups, scheduled reports, one-time migrations.
Most production microservices are Deployments with HPA, probes, and resource requests/limits configured.