Kubernetes has a reputation problem: it's described as a container orchestrator before anyone explains why orchestration is hard. The actual story is simple — running containers in production means answering endless operational questions: this container crashed, restart it. Traffic tripled, add replicas. Version 2 is broken, roll back. This node died, move everything. Kubernetes is one system that answers all of those declaratively: you describe desired state, it continuously reconciles reality toward it. Here are the concepts that make that click.
Pods: the smallest deployable unit#
A pod wraps one or more containers sharing network and storage — typically just one. Containers inside a pod share an IP and can talk over localhost.
Why not run containers directly? Because pods give Kubernetes a management unit: scheduling, scaling, and lifecycle operate on pods, not raw containers. Pods are also mortal by design — they get rescheduled onto different machines at any time, carrying no memory of their past. Everything durable must live outside the pod (volumes, databases, object storage). That assumption — pods are cattle, not pets — shapes every design decision in the ecosystem.
Deployments: why your app survives Wednesday#
You never manage pods directly; you declare a Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels: { app: api }
template:
metadata:
labels: { app: api }
spec:
containers:
- name: api
image: registry.example.com/api:v2.1
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }
This says: keep exactly 3 healthy copies of this image running. The deployment controller constantly reconciles — pod dies? recreate. Node drains? relocate. New image rolled out? replace pods gradually (rolling update), auto-rollback if health checks fail. The replica count plus self-healing loop is most of what people mean when they say "orchestration."
Services: stable networking over unstable pods#
Pods die and return with new IPs, so nothing can address them directly. A Service provides a stable virtual IP and DNS name fronting a changing set of pods (selected by label):
kind: Service
metadata:
name: api
spec:
selector: { app: api } # routes to matching pods
ports:
- port: 80
targetPort: 8080
Inside the cluster, http://api resolves and load-balances across current-healthy-pods automatically. Service types matter at the edges: ClusterIP (default, internal), NodePort, LoadBalancer (cloud LB). The label-selector mechanism is worth internalizing — loose coupling via labels is how K8s wires nearly everything together.
Ingress: HTTP routing from the outside world#
Services handle cluster-internal traffic; Ingress handles HTTP from outside — hostname and path routing through one entry point:
kind: Ingress
spec:
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend: { service: { name: api, port: { number: 80 } } }
- path: /
backend: { service: { name: web, port: { number: 80 } } }
One load balancer, many routed services, TLS termination included. (Modern clusters increasingly use the Gateway API for the same job — same concepts, cleaner model.)
ConfigMaps, Secrets, and Volumes#
- ConfigMap: environment config as first-class objects — inject values into pods without rebuilding images
- Secret: same idea for sensitive values (base64-encoded; pair with RBAC/encryption for real security)
- Volumes/PersistentVolumes: storage that outlives pod rescheduling — databases on K8s live or die by getting persistent volume claims right; stateless services mostly ignore all this
Scaling: the payoff#
kubectl scale deployment/api --replicas=10 # manual
The HorizontalPodAutoscaler automates it — scale replicas based on CPU/memory/custom metrics between min/max bounds. Combined with rolling updates, this is the elasticity pitch in two objects.
The daily kubectl set#
kubectl get pods -w # watch pods live
kubectl logs deploy/api -f # tail app logs
kubectl describe pod <name> # events = crash debugging gold
kubectl rollout restart deploy/api # bounce after config change
kubectl rollout undo deploy/api # instant rollback
kubectl apply -f manifest.yaml # declarative apply
Debugging workflow: get to spot unhealthy pods → describe for events (CrashLoopBackOff causes appear here) → logs for application errors. That loop handles most incidents before anything fancier.
Interview-ready summary#
Kubernetes reconciles actual state toward declared state. Pods = disposable process units; Deployments = self-healing replicated sets; Services = stable virtual IPs over changing pods; Ingress = external HTTP routing; Config/Secrets = environment injection; HPA = autoscaling. Know the reconciliation mental model plus the debug loop, and K8s questions become conversations instead of trivia exams.
Related: Docker foundations · Compose for local stacks · system design framework