Prerequisites
- A Kubernetes cluster — minikube or kind is enough for this lab
- kubectl installed and configured to point at that cluster
What You'll Learn
- Explain why Pods, not containers, are Kubernetes's atomic schedulable unit
- Use a Deployment to manage replica count and perform a rolling update / rollback
- Choose between ClusterIP, NodePort, and LoadBalancer Service types
- Debug a Pod stuck in CrashLoopBackOff or Pending
Theory
A Podis the smallest deployable unit in Kubernetes — one or more containers that always share the same network namespace (same IP, can reach each other via localhost) and can share storage volumes. Most Pods run a single container; a second "sidecar" container is added only when it must share that Pod's network/storage (a log shipper, a service mesh proxy).
Why not just run containers directly?
A Deployment doesn't manage Pods directly — it manages a ReplicaSet, which ensures a specified number of Pod replicas are running at all times, replacing any that die. The Deployment sits on top of that to manage rolling updates: when you change the Pod template (a new image tag, say), the Deployment creates a new ReplicaSet and gradually shifts traffic from old Pods to new ones, keeping a rollback point (the previous ReplicaSet) intact.
Service types
| Type | Reachable from | Typical use |
|---|---|---|
| ClusterIP | Inside the cluster only | Internal service-to-service traffic |
| NodePort | Any node's IP, on a static high port | Simple external access, dev/test |
| LoadBalancer | An external IP via the cloud provider's LB | Production external access |
Whichever type, a Service finds its target Pods by label selector — not by Pod name or IP, both of which change every time a Pod is recreated. This is why consistent labeling is foundational, not optional, in Kubernetes.
Architecture
A Deployment manages a ReplicaSet's Pod count; a Service load-balances across whichever Pods currently match its label selector
Hands-On Lab
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx:1.27
ports: [{ containerPort: 80 }]
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector: { app: web }
ports: [{ port: 80, targetPort: 80 }]kubectl apply -f deployment.yaml
kubectl get pods -l app=web # confirm 3 pods are Running
kubectl get deployment web
kubectl get svc web
# Trigger a rolling update to a new image tag
kubectl set image deployment/web web=nginx:1.27-alpine
kubectl rollout status deployment/web # watch the rollout progress
# Something wrong with the new version? Roll back instantly:
kubectl rollout undo deployment/web
kubectl rollout history deployment/webBest Practices
Always set resource requests and limits
Withoutresources.requests/limits, the scheduler can't make sensible placement decisions and a single runaway Pod can starve every other Pod on its node.Set readiness and liveness probes, not just a container that starts
A Pod reporting "Running" doesn't mean the application inside is actually ready to serve traffic — a readiness probe keeps it out of a Service's endpoint list until it genuinely is.Common Mistakes
Editing a running Pod directly instead of its Deployment
A Pod created by a Deployment is disposable by design — any directkubectl edit podchange is lost the next time that Pod is replaced. Always change the Deployment's template instead.Mismatched labels between Deployment template and Service selector
If the Service's selector doesn't exactly match the Pod template's labels, the Service silently has zero endpoints — `kubectl get endpoints web` showing empty is the tell.Troubleshooting
Pod stuck in CrashLoopBackOff: kubectl logs pod-name --previousshows the crashed container's output from before the restart (plain logs shows the new, possibly-empty attempt). kubectl describe pod pod-name shows the exit code and recent events — an exit code of 137 usually means the container was OOM-killed for exceeding its memory limit.
Pod stuck in Pending: kubectl describe pod pod-name's Events section explains why the scheduler can't place it — most commonly insufficient CPU/memory on any node, or an unsatisfiable node affinity/taint rule.
Frequently Asked Questions
Summary
Pods are the atomic unit, Deployments manage ReplicaSets to handle replica count and rolling updates/rollbacks, and Services provide a stable address in front of Pods that are constantly being replaced — all three composed together, matched by label selectors, is the core pattern behind almost every Kubernetes workload.