DevOps · Guide

Kubernetes

Pods, services, deployments, ingress, scaling.

— min read DevOps

Theory

Kubernetes orchestrates containers — master declarative desired state (Deployments, Services) and let the control plane reconcile.

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 / Secret

Examples

yaml — Deployment + Service
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
yaml — ConfigMap + Secret
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 }
bash — kubectl operations
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 requests and limits on every container — missing requests cause noisy-neighbor scheduling; missing limits allow OOM cascades.
  • Use readinessProbe separate from livenessProbe — 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 apply with version-controlled YAML, not imperative kubectl 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

Watch for these patterns — they cause most production incidents around Kubernetes.
  • Using latest image 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

kubectl get pods/svc/deployList core workload resources
kubectl describe podEvents, conditions, container state
kubectl logs -fStream pod container logs
kubectl exec -itShell into a running container
kubectl apply -fDeclarative create/update from YAML
kubectl rollout undoRollback deployment to previous revision
kubectl top nodes/podsCPU/memory usage (metrics-server)
requests vs limitsScheduler placement vs hard cap / OOM kill
liveness probeRestart container if app is deadlocked
readiness probeRemove pod from Service endpoints until ready

Practical Exercises

Deploy and scale

Write a Deployment + Service YAML for nginx with 3 replicas. Scale to 5 with kubectl scale. Delete a pod and watch it reschedule.

Rollout and rollback

Deploy v1, update image to v2, run kubectl rollout status. Introduce a broken v3, then kubectl rollout undo and verify traffic recovers.

Debug CrashLoopBackOff

Deploy a pod with a failing command. Use kubectl describe and kubectl logs --previous to find the error. Fix the manifest and re-apply.