Kubernetes
Pods, services, deployments, ingress, scaling.
Theory
Kubernetes orchestrates containers across a cluster of nodes. The control plane (API server, etcd, scheduler, controller manager) holds desired state; kubelet on each node runs containers via a container runtime (containerd). You declare intent in YAML; controllers reconcile reality.
A Pod is the smallest deployable unit — one or more containers sharing network namespace and volumes. Deployments manage ReplicaSets to run stateless apps with rolling updates. StatefulSets give stable network IDs and persistent volumes for databases. DaemonSets run one pod per node (log agents, node exporters).
Services provide stable cluster DNS names and load balancing to pods. ClusterIP (internal only), NodePort (host port), LoadBalancer (cloud LB), and Headless (direct pod DNS for StatefulSets). Selectors match pod labels — always version your labels and avoid mutable tags like :latest in prod.
Liveness probes restart unhealthy containers; readiness probes remove pods from Service endpoints until ready. Use HTTP /healthz, exec, or TCP checks. readiness must reflect dependency availability (DB connected); liveness should be lightweight to avoid restart loops.
resources.requests reserve scheduling capacity; resources.limits cap CPU (throttled) and memory (OOMKilled if exceeded). Set requests from production p95 usage; limits slightly above. Missing limits allow noisy neighbors; missing requests cause unpredictable scheduling.
ConfigMaps store non-sensitive config as key-value or files; Secrets store sensitive data (base64-encoded, not encrypted by default — enable encryption at rest). Mount as env vars or volumes. Prefer external secret operators (External Secrets, Vault) for rotation.
Ingress (with an Ingress controller like NGINX or Traefik) routes HTTP/S from outside the cluster to Services by hostname and path. NetworkPolicies restrict pod-to-pod traffic — default allow-all is risky in multi-tenant clusters.
kubectl is the primary CLI: apply -f manifest.yaml (declarative), get/describe for inspection, logs -f for streaming, exec -it for shells, port-forward for local debugging. Contexts and namespaces isolate environments — always specify -n production explicitly.
Architecture Diagram
kubectl / GitOps (ArgoCD)
|
API Server + etcd (desired state)
|
Scheduler --> Kubelet (nodes)
|
Pods + Services + Ingress
|
PersistentVolume / ConfigMap / SecretExamples
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
labels: { app: api }
spec:
replicas: 3
selector:
matchLabels: { app: api }
template:
metadata:
labels: { app: api }
spec:
containers:
- name: api
image: myregistry/api:1.2.0
ports: [{ containerPort: 8080 }]
resources:
requests: { cpu: "100m", memory: "128Mi" }
limits: { cpu: "500m", memory: "512Mi" }
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
initialDelaySeconds: 10
readinessProbe:
httpGet: { path: /ready, port: 8080 }
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector: { app: api }
ports:
- port: 80
targetPort: 8080
type: ClusterIP
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
LOG_LEVEL: info
FEATURE_FLAGS: "search=true,beta=false"
---
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
type: Opaque
stringData:
DATABASE_URL: postgres://user:pass@db:5432/app
---
# In Deployment spec.containers[0]:
# envFrom:
# - configMapRef: { name: api-config }
# env:
# - name: DATABASE_URL
# valueFrom:
# secretKeyRef: { name: api-secrets, key: DATABASE_URL }
kubectl apply -f deployment.yaml
kubectl get pods -n production -w
kubectl describe pod api-7f8b9c-xyz
kubectl logs -f deployment/api -n production
kubectl exec -it api-7f8b9c-xyz -- sh
kubectl port-forward svc/api 8080:80
kubectl rollout undo deployment/api
kubectl top pods -n production
Interview Questions
What is the difference between a Deployment and a StatefulSet?
Deployments manage stateless pods with random names and interchangeable replicas — rolling updates replace pods freely. StatefulSets assign stable hostnames (pod-0, pod-1), ordered startup/scale, and persistent volume claims per replica — for databases, Kafka, ZooKeeper.
When should you use a liveness probe vs a readiness probe?
Liveness: container is deadlocked — kubelet restarts it. Readiness: container cannot serve traffic yet (warming cache, waiting for DB) — removed from Service endpoints but not restarted. Never put dependency checks in liveness or you'll restart loops during upstream outages.
How do Kubernetes Services route traffic to pods?
Service has a ClusterIP and kube-proxy (iptables or IPVS) forwards to pod IPs matching label selectors. Endpoints object lists healthy pod IPs — readiness probe failures remove pods from endpoints. Headless Services (clusterIP: None) return pod A records directly.
What happens when a pod exceeds its memory limit?
The container is OOMKilled by the kernel (exit 137). Kubernetes restarts it per restartPolicy. No throttling like CPU — hard kill. Set limits from observed usage; use VPA recommendations or metrics-server data. Missing limits risk node-level OOM affecting other pods.
Explain the role of etcd in Kubernetes.
etcd is the distributed key-value store holding all cluster state (objects, desired spec). API server is the only component that writes etcd. Loss of etcd quorum loses cluster control plane — backup etcd and run odd-numbered replicas (3 or 5) across failure domains.
How do ConfigMaps differ from Secrets?
Both inject config into pods. Secrets are intended for sensitive data and stored base64-encoded; enable encryption at rest via KMS provider. Neither is encrypted in etcd by default without configuration. Mount Secrets as volumes for file-based config; env vars leak in process listings.
FAANG: How do you debug CrashLoopBackOff?
kubectl logs pod --previous for last crashed instance. kubectl describe pod for events (ImagePullBackOff, OOMKilled, failed probe). Check command/args, env vars, missing ConfigMaps. Run debug pod with sleep infinity and same volume mounts. Common causes: wrong entrypoint, missing secret, probe too aggressive before app starts.
What is the difference between requests and limits?
requests: scheduler uses to place pod on node with enough allocatable resources. limits: runtime cap — CPU throttled beyond limit, memory OOMKilled. Best practice: set requests ≈ steady-state usage, limits = requests or slightly higher for CPU, 1.2–2× for memory burst headroom.
Best Practices
- Set both
requestsandlimitson every container — missing requests cause noisy-neighbor scheduling; missing limits allow OOM cascades. - Use
readinessProbeseparate fromlivenessProbe— never restart pods that are temporarily slow to accept traffic. - Pin images by digest or immutable tag in production manifests — floating tags cause surprise rollouts.
- Use
kubectl applywith version-controlled YAML, not imperativekubectl create— drift becomes unrecoverable. - Define PodDisruptionBudgets before cluster upgrades — prevents voluntary evictions from taking down all replicas.
- Label everything consistently (
app,env,version) — selectors and NetworkPolicies depend on them.
Common Mistakes
- Using
latestimage tags in Deployment specs — nodes pull different versions; rollouts become non-deterministic. - Omitting resource requests — pods pack onto nodes until the kernel OOM-kills random processes cluster-wide.
- Liveness probe hitting the same endpoint as readiness with tight timeouts — transient slowness causes restart loops.
- Running one replica of stateful services with no PDB — a single node drain takes the service offline.
- Granting cluster-admin to CI service accounts — one leaked token compromises the entire cluster.
Cheat Sheet
Practical Exercises
Write a Deployment + Service YAML for nginx with 3 replicas. Scale to 5 with kubectl scale. Delete a pod and watch it reschedule.
Deploy v1, update image to v2, run kubectl rollout status. Introduce a broken v3, then kubectl rollout undo and verify traffic recovers.
Deploy a pod with a failing command. Use kubectl describe and kubectl logs --previous to find the error. Fix the manifest and re-apply.