Kubernetes I — Pods, Deployments, Services
Trace desired-state reconciliation across Pods, Deployments and Services; reason about selectors, probes, scheduling, storage, security and rollout failures.
Original publication date unrecordedUpdated
Lesson preparation & details
Level: intermediate
By the end, you should be able to
- Trace Pod ownership, scheduling, probes and Service endpoint eligibility
- Distinguish rejected Deployment selectors from disconnected Service selectors
- Read and test local manifests and rollout/QoS/PDB constraints without availability guarantees
Bring with you
Sources checked: . A source check does not change the publication or update date.
Editorial review: · What review means
In this article · 37 sections
Review and execution boundary
Kubernetes apps/v1 Deployments, v1 Services; manifest reasoning only, no cluster execution.
Historical conceptual-review notes are dated 7 October 2026. This current body was freshly reviewed on 10 October 2026, including original objectives, mechanisms, examples and individual worked assessments. Exact safe local fixtures and scoped MDX checks are recorded separately in the review evidence. No Azure/IAM writes, Kubernetes cluster, .NET/Bicep compilation or cloud service reproduction was performed; installed-tool availability and each executed model are named in that evidence. Optional deployment commands are learner exercises, not completed actions.
module: M07 · Systems & Infrastructure sessionNo: 66 track: SYS minutes: 90 goal: Understand Pod, Deployment, Service, and Ingress; deploy a 2-replica app to kind and hit it through a Service.
Why this session exists
Kubernetes coordinates containerized workloads through APIs and reconciliation. Pod, Deployment, Service and Ingress form a useful first path from workload to traffic. HPA, ConfigMap and StatefulSet are not decoration: they address scaling, configuration and stateful identity that this first path does not solve.
title: You will be able to items: Explain Pod vs Deployment vs Service vs Ingress to a friend in under two minutes. — Write valid YAML for a 2-replica web app with a ClusterIP service and read it with kubectl. — Deploy to a local kind cluster, kill a pod, and watch the Deployment respawn it. — Diagnose the top-3 K8s beginner traps: label mismatches, unbounded resources, and CrashLoopBackOff loops.
Prerequisites
- S065 · Docker — you can build and run container images.
- S062 · Load balancers — reverse-proxy + health-check mental model.
- S060 · Linux fundamentals — processes, network namespaces.
Pre-read and pacing
Select about 25 minutes of pre-reading; do not add all six resources to that budget. The 5/15/25/15/10-minute section estimates sum to 70 minutes; 25 minutes of pre-reading would make 95. The original 90-minute label is approximate, not an exact total or an execution measurement. Historical video title/channel/duration labels are retained below but playback, attribution and current UI have not been verified.
url: https://www.youtube.com/watch?v=PziYflu8cB8 title: Kubernetes in 100 Seconds channel: Fireship minutes: 2 why: Optional short Kubernetes introduction; “tightest” was subjective and repeated viewing is optional.
url: https://www.youtube.com/watch?v=X48VuDVv0do title: Kubernetes Tutorial for Beginners · Full Course channel: TechWorld with Nana minutes: 240 why: Skip to sections 3-6: Pods, Deployments, Services. The rest is bonus material for later sessions.
url: https://www.youtube.com/watch?v=s_o8dwzRlu4 title: Kubernetes Crash Course for Absolute Beginners [NEW] channel: TechWorld with Nana minutes: 22 why: Original hands-on video recommendation; not verified as a kind walkthrough or a current click-path. Use the explicit reference script and versioned documentation below for the actual exercise.
url: https://kubernetes.io/docs/concepts/workloads/pods/ title: Pods · Kubernetes concepts source: Kubernetes docs · official minutes: 10 why: The canonical explanation of the pod abstraction. Skim; you'll return here often.
url: https://kubernetes.io/docs/tutorials/kubernetes-basics/ title: Kubernetes Basics · interactive tutorial source: Kubernetes docs · official minutes: 30 why: Optional guided basics companion. Tutorial content is useful reading; availability of an in-browser interactive environment has not been verified.
url: https://cloud.google.com/blog/products/gcp/kubernetes-101-networking title: Kubernetes 101 · Networking source: Google Cloud Blog minutes: 15 why: How pods get IPs, how Services find pods — the model that Ingress builds on.
(a) Intuition · 5 min
A hotel with a smart concierge
Think of a Pod as a suite of co-located containers sharing networking and explicitly mounted volumes. A Deployment is the supervisor declaring the desired number and version of suites; its ReplicaSets create replacement Pods. A Service supplies a stable discovery/routing abstraction for eligible backends. An Ingress declares HTTP host/path rules; a compatible controller implements them. The analogy stops at guarantees: insufficient capacity, bad images or failing readiness can prevent the desired state becoming available.
The four objects that carry the initial mental model
- Pod: one or more containers scheduled together, with a shared network namespace. Each container still has its own filesystem unless a volume is mounted into both. A port number on a shared address cannot be independently bound by two ordinary listeners.
- Deployment: manages ReplicaSets and rolling Pod-template versions for replaceable workloads. It does not itself execute containers or fix application bugs.
- Service: the ordinary ClusterIP form provides a stable virtual address and DNS name. A selector drives EndpointSlice membership; readiness affects eligibility. Headless, selectorless and ExternalName Services differ from that default model.
- Ingress: a separate networking API, not a Service type. It requires a controller and configured ingress/TLS behavior. The Ingress API is frozen; Kubernetes recommends Gateway API for newer capabilities where a supported implementation fits.
The declarative principle to internalise
kubectl apply submits desired state. Independent control loops react to observed changes: Deployment → ReplicaSet → Pod, scheduler → node binding, kubelet → container runtime. They are asynchronous but not arbitrary: the scheduler cannot bind a Pod that does not yet exist. API admission errors, Pending reasons and rollout-progress conditions expose failures; reconciliation is not an infinite silent success. Deleting a managed Pod normally leads to a replacement with a new UID, not resurrection of the same Pod.
A quick history so the ecosystem makes sense
The Kubernetes project’s 6 June 2024 retrospective records the first commit on 6 June 2014, public announcement on 10 June, and v1.0 on 21 July 2015 alongside the CNCF donation announcement. It traces the ideas to Borg/Omega and the small team working in 2013—not a claim that one person invented all orchestration. In December 2017, the Workloads API reached GA, stabilizing Deployment/ReplicaSet. December 2020 deprecated dockershim; May 2022 / v1.24 removed it. These milestones explain API stability and runtime separation better than saying Kubernetes “won” in one year.
The useful historical distinction is runtime versus image tooling: Kubernetes removed its built-in dockershim integration in v1.24. Docker-built OCI-compatible images remain usable with a supported CRI runtime such as containerd. This does not mean Docker image tooling was removed or that all clusters must use one runtime. Kubernetes descends from Google's experience with cluster scheduling; historical adoption slogans are not operational guarantees.
The object hierarchy — how the four pieces connect
Connect the four Kubernetes objects by following an incoming request towards the web pods. The Deployment groups the replicas, while the Service selects the pods that traffic can reach.
Figure text equivalent — labels and relationships
- Node “Ingress public HTTPS routing” (square).
- Node “Service · app-svc ClusterIP 10.96.5.3 selector: app=web” (square).
- Node “Service · api-svc ClusterIP 10.96.5.4” (square).
- Node “Pod web-abc label: app=web” (square).
- Node “Pod web-def label: app=web” (square).
- Node “Pod web-ghi label: app=web” (square).
- Group “Deployment · web (replicas: 3)” contains “Pod web-abc label: app=web”, “Pod web-def label: app=web”, “Pod web-ghi label: app=web”.
- “Ingress public HTTPS routing” leads to “Service · api-svc ClusterIP 10.96.5.4”: host=example.com path=/api. Line: normal; ends: arrow point.
- “Ingress public HTTPS routing” leads to “Service · app-svc ClusterIP 10.96.5.3 selector: app=web”: host=example.com Prefix path=/. Line: normal; ends: arrow point.
- “Service · app-svc ClusterIP 10.96.5.3 selector: app=web” leads to “Pod web-abc label: app=web”. Line: dotted; ends: arrow point.
- “Service · app-svc ClusterIP 10.96.5.3 selector: app=web” leads to “Pod web-def label: app=web”. Line: dotted; ends: arrow point.
- “Service · app-svc ClusterIP 10.96.5.3 selector: app=web” leads to “Pod web-ghi label: app=web”. Line: dotted; ends: arrow point.
Reading the diagram: an ordinary ClusterIP is a virtual address implemented by the cluster's service dataplane. kube-proxy can program iptables, nftables or supported platform-specific rules; other implementations can use eBPF. Backend selection is implementation/configuration dependent, not universally round-robin. DNS resolves a Service name; a successful DNS lookup alone does not prove any backend is ready. The Deployment box denotes ownership, not a network hop.
The lifecycle of a Deployment rollout
- Submit a valid Pod-template change to the API server; admission/policy may reject it.
- The Deployment controller creates/scales ReplicaSets under the rollout budget.
- The ReplicaSet controller creates Pods; the scheduler selects suitable nodes using requests, placement constraints and available capacity.
- Kubelet pulls the image and starts containers through the runtime; image pull/startup can fail independently of scheduling.
- Startup/readiness probes and readiness gates determine eligible traffic endpoints. Running is a Pod phase, not a synonym for Ready.
- The Deployment scales old/new ReplicaSets subject to availability and surge settings. Retained ReplicaSets enable a rollback attempt, not instantaneous recovery; images, capacity and dependencies must still work.
The four Service types you'll actually use
| Exposure | Mechanism | Boundary |
|---|---|---|
| ClusterIP | Stable cluster virtual IP and Service DNS | Normally reached from cluster networking, not automatically from a laptop |
| NodePort | Allocated port on eligible node addresses (default range 30000–32767) | Firewalls, node address selection and networking still matter |
| LoadBalancer | Requests a supported load-balancer implementation | Provisioning and public/internal addresses depend on provider/configuration; kind alone does not supply a cloud LB |
| ExternalName | DNS alias to an external name | Does not create a proxy or ordinary Pod selector routing |
Ingress can front multiple Services using host/path/TLS rules; its controller may itself be exposed through a LoadBalancer Service. A single IP or nginx controller is not intrinsic to the Ingress API.
YAML anatomy — the shape you'll write a hundred times
For Deployment and Service manifests, apiVersion, kind, metadata and spec identify the API, object, name/labels and desired configuration. Not every Kubernetes object has a spec (ConfigMap uses data), so this is an anatomy of these workload/network resources, not a universal schema.
Selector validation versus disconnected routing
An apps/v1 Deployment with selector app: web but template labels app: webapp is rejected by API validation. It does not create infinitely many phantom Pods. A separately valid Service with selector app: webapp can exist alongside Pods labeled app: web and select none. Check namespace, selectors, EndpointSlices, readiness, targetPort and actual listener in that order; names alone do not join resources.
Why a Pod groups containers
A sidecar and application may need localhost communication or a shared mounted volume, so scheduling them together preserves locality. One Pod network namespace gives them a shared port space; volume sharing is explicit, not automatic filesystem sharing. This enables some service-mesh sidecar designs, but traffic interception still needs a configured implementation and is not a guarantee for every protocol. Most Pod fields are immutable; direct changes to some fields (including container image) are allowed. A Deployment Pod-template change normally produces new Pods through a new ReplicaSet, which is the versioning mechanism taught here.
A thermostat, not a remote control
Controllers compare desired and observed state, but different loops have different duties. ReplicaSets replace missing Pods; kubelet restarts containers within a Pod according to restart policy. A bare Pod can have its container restarted but is not rescheduled as the same Pod onto another node. API objects such as Secrets are not each paired with their own healing controller. Read Events, conditions and logs together rather than assuming one command contains the whole incident.
- Readiness failure makes endpoints unsuitable for normal Service traffic; EndpointSlices can still record an endpoint with
ready: false. Liveness failure causes a container restart, not necessarily Pod replacement. Startup probes postpone liveness/readiness checks until successful startup. Do not make a shared database outage restart all healthy application processes. - CPU requests influence scheduling and relative CPU allocation under contention; limits can throttle. A request is not a universal hard cap. Memory limits are enforced reactively through OOM behavior; node pressure may cause eviction before an application reaches its own limit.
- Endpoint discovery and termination updates are asynchronous. Graceful shutdown needs a draining application and an appropriate grace period, not just a YAML label.
Requests, limits and QoS: worked capacity decision
For the traditional per-container Guaranteed QoS rule, every container needs nonzero CPU and memory requests equal to the corresponding limits. Only matching memory is insufficient. Guaranteed does not isolate every shared disk/network/CPU resource or guarantee zero eviction. Burstable Pods have some requests/limits but do not meet that full equality rule; BestEffort has neither. Newer Pod-level-resource features have version/feature-gate nuances, so the lab uses per-container resources only.
Consider a node with 1,000m allocatable CPU and 1 GiB memory. Two lab Pods request 50m/32Mi each, so the scheduler accounts for 100m/64Mi before other workloads; it does not reserve each Pod's 200m/128Mi limit as the scheduling request. A surge Pod adds another 50m/32Mi of requested capacity. Other workloads, daemon overhead and placement constraints can still prevent it fitting.
Matching requests to peak limits makes capacity planning conservative and reduces scheduling overcommit; it does not make unused CPU physically unavailable to other processes. Smaller requests allow more scheduled workloads but may misrepresent realistic contention. Omitting memory limits avoids a per-container cap but can amplify node pressure: use measured headroom and an explicit shared-cluster admission policy rather than a universal “always equal” rule. Profile startup and steady state; p99 alone may miss rare but legitimate bursts.
Storage and security are explicit contracts
The lab nginx containers are replaceable serving replicas, not a persistence design or a restricted-security example. Container writable-layer data can be lost when a container is replaced. An emptyDir belongs to the Pod lifetime: it survives a container restart inside that Pod, but not deletion of the Pod. A mounted PVC requests persistent storage through a PV/StorageClass/provisioner; binding mode, access mode, zone/node topology and backend availability can constrain scheduling. A pending claim can keep a Pod Pending even when CPU and memory fit. Persistence is not a backup, and a Deployment's multiple replicas do not make a single-writer volume safely writable by all of them.
The ConfigMap stretch mounts configuration, not durable user data. Projected file updates are eventually visible under the documented rules; applications still need to reread files, environment variables are not live-refreshed, and a subPath ConfigMap mount does not receive normal projected updates. A StatefulSet adds stable identity/storage associations when appropriate; it is not a database consistency or backup engine.
For a Linux restricted-policy deployment, review non-root execution, an explicit compatible UID, allowPrivilegeEscalation: false, dropped capabilities and a supported seccomp profile. Read-only root filesystems and explicit writable mounts are additional design choices. A stock nginx image listening on port 80 may need a different image, listener port and writable paths before such a policy works; do not paste a securityContext and assume the example will start. ServiceAccount credentials, RBAC, secrets access and hostPath/daemon-socket mounts are separate authority boundaries. NetworkPolicy requires an enforcing network implementation and explicit policy; creating a Service does not isolate the application.
Worked failure. Two replicas request the same single-writer storage in incompatible placement zones. More CPU does not fix mount/topology rejection. Inspect PVC/PV binding, access modes, scheduler Events and application write coordination. A ConfigMap mount cannot substitute for that claim, and increasing a PDB cannot restore lost data. Admission and actual mount behavior remain unexecuted in this review.
(c) Hands-on · 25 min
Optional native exercise, not run here: in a separately authorized disposable environment, create a kind cluster, deploy two web replicas, expose them with a Service and observe a managed Pod replacement. This is a recovery observation, not a proof of availability. Do not reuse a pre-existing exercise cluster or switch an unrelated context.
#!/usr/bin/env bash
# s066-k8s-demo.sh — optional disposable local-cluster exercise, not executed here.
# Requires: docker, kubectl, kind (https://kind.sigs.k8s.io/)
set -euo pipefail
DIR="$HOME/projects/learning/s066"
mkdir -p "$DIR" && cd "$DIR"
log() { printf "\033[1;36m▶ %s\033[0m\n" "$*"; }
log "1/5 Creating a local kind cluster"
if kind get clusters | grep -Fxq s066; then
echo "s066 already exists; stop and establish ownership before continuing" >&2
exit 1
fi
kind create cluster --name s066
kubectl() { command kubectl --context kind-s066 "$@"; }
kubectl cluster-info
log "2/5 Writing the manifest (Deployment + Service)"
cat > web.yaml <<'YAML'
# ---- Deployment: 2 pods of nginx, each labelled app=web ----
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 2
selector:
matchLabels:
app: web # <-- MUST match template.metadata.labels
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # allow +1 pod during a rollout
maxUnavailable: 0 # controller rollout budget, not an outage guarantee
template:
metadata:
labels:
app: web # <-- MUST match spec.selector.matchLabels
spec:
containers:
- name: nginx
image: nginx:1.27-alpine # historical lab image; choose a reviewed supported digest for new use
ports:
- containerPort: 80
resources:
requests: { cpu: "50m", memory: "32Mi" } # scheduler accounts for these requests
limits: { cpu: "200m", memory: "128Mi" } # CPU quota throttles; memory enforcement can OOM
readinessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet: { path: /, port: 80 }
initialDelaySeconds: 10
periodSeconds: 10
---
# ---- Service: one stable ClusterIP that fronts both pods ----
apiVersion: v1
kind: Service
metadata:
name: web-svc
labels:
app: web
spec:
type: ClusterIP
selector:
app: web # <-- MUST match the pod labels above
ports:
- port: 80 # the Service's port
targetPort: 80 # the container's port
YAML
log "3/5 Applying the manifest"
kubectl apply -f web.yaml
kubectl rollout status deployment/web --timeout=60s
log "4/5 Inspecting what got created"
kubectl get pods,svc,deploy -l app=web -o wide
echo
echo "--- Endpoints backing the service ---"
kubectl get endpointslices -l kubernetes.io/service-name=web-svc
log "5/5 Observe reachability and replacement (not a load-distribution proof)"
# Hit the Service from a temporary pod (Services aren't reachable from your laptop directly with kind)
kubectl run curl-test --rm -i --restart=Never --image=curlimages/curl:8.9.1 -- \
sh -c 'for i in 1 2 3 4; do curl -s -o /dev/null -w "%{http_code} served by %{remote_ip}\n" http://web-svc; done'
echo
echo "--- Delete one pod and watch it come back ---"
POD=$(kubectl get pod -l app=web -o jsonpath='{.items[0].metadata.name}')
echo "killing $POD"
kubectl delete pod "$POD"
kubectl rollout status deployment/web --timeout=60s
kubectl get pods -l app=web -o wide
echo
echo "--- Check rollout history (initial revision should be present) ---"
kubectl rollout history deployment/web
echo
echo "For a version exercise, choose a reviewed alternate digest, then set the image:"
echo " kubectl set image deployment/web nginx=REVIEWED_IMAGE_DIGEST && kubectl rollout status deployment/web"What each block does
The Deployment selector must match its template, and the Service selector must match the intended Pods. containerPort is documentation for the declared port; it does not create a listener. The readiness and liveness HTTP probes exercise nginx's root path in this small lab. They do not prove every application dependency or user journey is healthy.
What to observe and what not to infer
- Two desired Pods get generated names and UIDs. The
pod-template-hashdistinguishes ReplicaSet templates; it is not simply the Deployment generation number. - After deleting one Pod, the ReplicaSet attempts replacement; there is no guaranteed “within seconds” recovery. Record old/new UIDs and availability.
- Inspect EndpointSlice addresses and readiness conditions. Legacy Endpoints is deprecated in Kubernetes v1.33; it also represented not-ready addresses separately, so “always only ready” was inaccurate.
- Curl's
remote_ipfor a Service request normally identifies the Service address from the client's perspective, not a reliable selected backend identity. Four HTTP 200s prove those requests succeeded, not fairness or round-robin distribution. A backend response containing its own Pod identity is needed for that observation.
Break and recover: image failure is not application crash
In the disposable context only, changing nginx to a nonexistent tag produces image-pull errors/ImagePullBackOff. No container ran, so CrashLoopBackOff is a different experiment: a pullable image with a process that repeatedly exits. Inspect Events, container state/lastState and kubectl logs --previous where a prior container actually started. Backoff defaults and feature-gated reductions vary by Kubernetes version; do not confuse image-pull retry with container restart timing.
kubectl --context kind-s066 set image deployment/web nginx=nginx:doesnotexist
kubectl --context kind-s066 describe deployment web
kubectl --context kind-s066 get pods -l app=web
# Recovery attempts to restore the previous Pod template, not database state.
kubectl --context kind-s066 rollout undo deployment/web
kubectl --context kind-s066 rollout status deployment/web --timeout=60sUse kind delete cluster --name s066 only after verifying it is the disposable exercise cluster and no unrelated work depends on it. This is an optional learner action, not a command run during the review.
(d) Production reality · 15 min
Upgrade, memory and selector failure analyses
Upgrade: a synthetic cluster upgrade changes a networking component's behavior; requests fail although application Pods are Running. Compare node/runtime/CNI/DNS versions, service dataplane state and release notes; test a representative staging workload before broader rollout. The former Reddit-specific DNS/Redis story was not substantiated and is not asserted here. The lesson is to investigate actual control/data-plane evidence, not to copy an invented incident fix.
Memory: an unbounded or underestimated workload can create node pressure and evict neighbors. Kernel OOM victim choice involves memory use and oom_score adjustments, not always “kill the biggest process”. Requests affect placement/QoS; measured limits and admission policy help contain risk but cannot guarantee no outage. Inspect whether the failure was container OOMKilled or node-pressure eviction before changing settings.
Disconnected Service: app: myapp differs from app: my-app. The Service and Deployment may both validate while no eligible endpoints are selected. A client might time out, receive connection refusal or see a proxy-generated 503; a Service does not universally emit HTTP 503. Generated labels in Helm/Kustomize reduce duplication, but tests must still verify selectors, namespace and readiness.
Common footguns to internalise
- CrashLoopBackOff without logs — the app crashes so fast that logs are empty. Try
kubectl logs <pod> --previousto get the last dying breath. - imagePullPolicy: Always with :latest — the runtime resolves the tag on each container start; matching cached image layers can be reused. Combined with mutable :latest, every restart is a Russian roulette deploy.
- Missing PodDisruptionBudget — cluster maintenance drains a node, all your replicas get evicted simultaneously, zero downtime turns into an outage. A PDB restricts supported voluntary Eviction API requests; it cannot prevent node failure, direct Pod deletion or every Deployment rollout. Choose minAvailable/maxUnavailable relative to replicas and capacity.
- No graceful shutdown — endpoint changes, preStop hooks and application draining are asynchronous. The default grace period is 30 seconds, not a magic fix. Choose a measured budget, account for hook time within it and handle the configured stop signal; expiry can force termination.
Where this shows up in the rest of the plan
root: Kubernetes basics feed every following ops session branches: label: S067 · Kubernetes advanced; desc: ConfigMaps, Secrets, HPA autoscaling, NetworkPolicies. Builds directly on this session.; tone: violet — label: S068 · Azure Cloud; desc: AKS = managed K8s. The four objects here are exactly what you deploy on AKS.; tone: cyan — label: S069 · IaC · Terraform; desc: Terraform provisions the cluster; K8s manifests deploy INTO it. Two layers of IaC.; tone: emerald — label: S078 · SRE · SLOs; desc: Pod-level metrics via Prometheus; per-Deployment SLO burn rates.; tone: amber — label: S085 · Security · pod security; desc: PSA, admission controllers, network policies. The security layer on top.; tone: rose — label: S095 · System design · microservices; desc: A replaceable serving microservice often uses a Deployment and Service; jobs and stateful workloads have different controllers.; tone: sky
(e) Recall + stretch · 10 min
Worked recall answers
1. Pod, Deployment and Service
Question: One-sentence definitions of Pod, Deployment, Service.
Answer: Pod is the co-located scheduling unit; Deployment versions/manages ReplicaSets; an ordinary selector-based Service provides stable discovery/routing to eligible backends. None guarantees availability by existing alone.
2. Bare Pod or workload controller
Question: Why do you almost never create a Pod directly?
Answer: A bare Pod can restart containers but lacks a workload controller to replace it after deletion/node loss. Prefer Deployment for replaceable serving replicas and Job/CronJob for finite work.
3. Probe responsibilities
Question: What's the difference between readinessProbe and livenessProbe?
Answer: Readiness controls traffic eligibility; liveness restarts a failed container; startup protects legitimately slow initialization. A failing database should generally not make every application container fail liveness.
4. Scheduler requests
Question: Why do resource requests matter to the scheduler?
Answer: Requests are scheduler accounting and resource-allocation inputs. Admission may default missing requests (including from a specified limit), so “no field always means zero” is not universal. Inspect the admitted Pod, not just the input YAML.
5. Changed image without replacement
Question: You changed the image but pods didn't restart. Why?
Answer: Editing a local file is not applying it. Updating a Deployment's Pod template normally creates a new ReplicaSet; reusing the identical image string may not change that template. ConfigMap projection and environment values have different update behavior; neither implies an automatic application restart.
6. ClusterIP traffic path
Question: What is a ClusterIP, and how does traffic actually reach a pod behind one?
Answer: Service DNS resolves a ClusterIP; the dataplane selects an eligible endpoint according to implementation/policy. iptables is not universally round-robin, and eBPF/nftables implementations exist.
7. Host and path routing
Question: You want to route example.com/api to service A and other paths to service B. Which object do you use?
Answer: Host/path routing can use Ingress plus controller or Gateway API plus implementation. With Ingress use supported pathType semantics (for example Prefix /api and Prefix /), not an assumed universal /* wildcard.
8. Deleting a Pod versus its Deployment
Question: What's the practical difference between deleting a Pod and deleting the Deployment that owns it?
Answer: Deleting a managed Pod triggers replacement attempts; deleting the Deployment normally garbage-collects dependent ReplicaSets/Pods unless orphaning behavior is chosen. Deleting the object is not the same as stopping all independently managed resources with similar labels.
9. Rollout budgets
Question: Explain the rolling update parameters maxSurge and maxUnavailable.
Answer: For desired 3 with maxSurge 1 and maxUnavailable 0, the rollout can request an extra Pod while preserving the controller's available-replica budget. Capacity/probes may stall it; independent failures can still reduce availability and terminating Pods may temporarily consume extra resources. Percentage surge rounds up and unavailable rounds down.
Stretch answer: configuration and disruption budget
Question: Sketch three replicas with DEBUG=true, app-config mounted at /etc/config, and a disruption budget protecting two healthy replicas during supported voluntary eviction. Why can it not guarantee two are always available?
The ConfigMap is defined, mounted read-only and the DEBUG environment string is quoted. The PDB permits at most one voluntary eviction when all three matching Pods are healthy; it is not a promise that two always survive any failure. The image is the same historical local-lab pin, not a production security recommendation.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
mode: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: app
image: nginx:1.27-alpine
env:
- name: DEBUG
value: "true"
resources:
requests: { cpu: "50m", memory: "32Mi" }
limits: { cpu: "200m", memory: "128Mi" }
readinessProbe:
httpGet: { path: /, port: 80 }
volumeMounts:
- name: cfg
mountPath: /etc/config
readOnly: true
volumes:
- name: cfg
configMap: { name: app-config }
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels: { app: web }Offline selector model
This exact pure function is tested locally with matching, mismatching, wrong-namespace and not-ready fixtures. It models eligible label-selected traffic; it does not emulate EndpointSlice controllers, terminating endpoints or publishNotReadyAddresses.
def eligible_backends(service, pods):
selector = service.get("selector", {})
if not selector:
return [] # this model covers only selector-based Services
return [p["name"] for p in pods
if p["namespace"] == service["namespace"]
and p["ready"]
and all(p["labels"].get(k) == v for k, v in selector.items())]Worked failure: three Running Pods in default labeled app=web produce zero eligible backends for selector app=api. Changing the selector to app=web yields only ready Pods; increasing replicas without fixing the selector yields zero again. A Deployment selector/template mismatch is rejected at admission instead—test that as a separate manifest invariant.
Explain-out-loud test
- What's the difference between a Pod and a Deployment?
- How does a Service find the pods it routes to? (label selector + endpoints)
- Name two things you must set on every production pod. (resources · readinessProbe · non-root user · terminationGracePeriodSeconds)
What comes next
Previous: S065 · Docker. Next: S067 · Kubernetes advanced (continuation destination retained; not reviewed by this batch).
Hub: The 6-Month Learning Plan
Part of a 130-session evergreen learning series. Session structure: intuition → visual → hands-on → production war stories → recall. Duration: an estimated 90 minutes including selected pre-reading; a native cluster lab can take longer.
Corrected contracts and failure analysis
A Deployment owns ReplicaSets, which own Pods; desired replicas are not a guarantee that scheduling or readiness succeeds. Service selectors match labels, not Deployment names. The Service's targetPort must match a real listening container port. A containerPort declaration does not itself open a process listener.
Readiness removes a Pod from suitable service traffic paths; liveness restarts a failed container. An external database outage should not usually fail liveness, or every replica can restart at once. Use a startup probe for legitimately slow startup. A rollout can stall when surge Pods cannot fit available capacity; maxUnavailable and maxSurge interact with resource requests, not just replica arithmetic. LoadBalancer provisioning and public exposure depend on the cluster implementation.
Boundary exercise with solution
A new Deployment has three Running Pods but its Service has no endpoints. What do you inspect first?
Solution and reasoning
Check Service selector labels against Pod labels, namespace, readiness conditions and EndpointSlices. Running only means the Pod phase, not application readiness. Then inspect targetPort and actual bind address. Changing the replica count does not repair a selector mismatch.
Source-backed review notes
Official/maintainer snapshots were retrieved and hash-checked on 7 October 2026. The review evidence retains exact supporting passages, document dates and hashes; mutable documentation is not a pin to an installed service/runtime version.
-
Deployments | Kubernetes — Deployment selector/template mismatch is rejected by the API, not infinite Pod creation.
-
Pods | Kubernetes — Pod scheduling/network/volume sharing is not a universal shared root filesystem.
-
Service | Kubernetes — EndpointSlice replaces deprecated Endpoints and exposes distinct endpoint metadata.
-
Virtual IPs and Service Proxies | Kubernetes — iptables default backend selection is random, not universal round-robin; implementation matters.
-
Resource Management for Pods and Containers | Kubernetes — Memory limits are reactive; request defaulting and resource semantics need qualification.
-
Pod Quality of Service Classes | Kubernetes — Traditional Guaranteed requires CPU and memory equality on every container, not memory alone.
-
Disruptions | Kubernetes — PDB does not govern Deployment rolling updates or guarantee immunity to involuntary failure.
-
Ingress | Kubernetes — Ingress remains available but new development is directed toward Gateway API.
-
10 Years of Kubernetes | Kubernetes — First commit/public history is date-specific primary retrospective, not adoption folklore.
-
Updated: Dockershim Removal FAQ | Kubernetes — Dockershim removal concerns runtime integration, not a ban on Docker-built images.
Original incident reading and review context
Reddit’s Pi Day Recovery remains the original optional operator-incident reading. This review does not use the old DNS/Redis/CoreDNS narrative as verified evidence, nor promise that the historical URL is currently reachable. Read the operator’s actual report before attributing an exact cause, fix or 314-minute figure. The upgrade exercise above preserves the diagnostic function without inventing those particulars.
Current source and verification boundary
Fresh body review: 10 October 2026. The following official primary sources were saved as raw and canonical bytes with exact supporting quotations in the batch-37 evidence packet. Docker documentation is pinned to a repository commit, not a claim that every Engine 28+ release behaves identically; Kubernetes sources are pinned to the release-1.34 documentation branch commit, not to a running cluster. RFC numbers and the OCI/Varnish tags identify their respective contracts. Historical package/image tags in the examples remain reference inputs, not current vulnerability approval.
- k8s-deployment — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-probe-task — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-service — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-resources — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-volumes — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-configmap — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-security — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-qos — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
- k8s-pdb — 47132eb5367cfdcba0a3b33a0b3ffc81185bd7e8.
Only the stated CPU models and static source/syntax checks are evidence from this review. No container, image build, Varnish listener, provider purge, Kubernetes cluster, browser application rendering or site deployment was executed. Preserved resource links are reading recommendations; videos and unverified historical pages are not evidence of a runtime result.
Pause / Recall / Apply
Can you explain it without the page?
Close the example. Reconstruct the core idea, then change one assumption. Mark complete when you’re ready; you can always undo it.
Stored in this browser only. No account, no sync. Clearing browser data removes your record.