Kubernetes Interview Questions — 40 with Real Answers
If you are interviewing for a DevOps engineer, platform engineer, SRE, or backend engineering role at any company running cloud-native infrastructure, you will be asked Kubernetes questions. Not trivia — working questions that separate engineers who have operated clusters under pressure from engineers who have only read the docs.
This guide covers 40 questions organized by topic, each with the answer an experienced engineer would give, the YAML or kubectl command you should be ready to write on a whiteboard, and what the interviewer is actually testing.
Cluster Architecture
1. Explain the Kubernetes control plane. What happens when you run kubectl apply?
The control plane consists of four main components: the API server (single entry point for all REST operations), etcd (distributed key-value store that is the cluster's source of truth), the scheduler (assigns pods to nodes based on resource requests and constraints), and the controller manager (runs reconciliation loops for Deployments, ReplicaSets, etc.).
When you run kubectl apply -f deployment.yaml:
- 1
kubectlsends aPATCHorPUTrequest to the API server with your manifest. - 2The API server authenticates, authorizes (RBAC), and validates the object, then persists it to etcd.
- 3The Deployment controller (inside controller manager) detects the new/changed Deployment and creates or updates a ReplicaSet.
- 4The ReplicaSet controller creates Pod objects in etcd.
- 5The scheduler watches for unscheduled pods, picks a node, and writes the node name into the pod's spec.
- 6The kubelet on the chosen node watches for pods assigned to it, pulls images, and starts containers via the container runtime (containerd or CRI-O).
What interviewers test: whether you understand declarative reconciliation versus imperative commands. The cluster always moves toward desired state — nothing runs commands, everything reacts to state changes in etcd.
2. What is the difference between a kubelet and kube-proxy?
The kubelet runs on every node and is responsible for managing the pod lifecycle: it watches for pods assigned to its node, ensures containers are running and healthy, reports node and pod status back to the API server, and enforces liveness/readiness probes.
kube-proxy runs on every node and is responsible for network rules. It watches for Service and Endpoint objects and programs iptables (or IPVS) rules so that traffic sent to a ClusterIP or NodePort gets forwarded to the correct pod IPs. In modern clusters using a CNI plugin like Cilium, kube-proxy is often replaced entirely.
What interviewers test: whether you conflate node-level compute management with node-level networking.
Pods
3. What is a Pod and when would you run multiple containers in one?
A Pod is the smallest deployable unit in Kubernetes. It is a group of one or more containers that share the same network namespace (same IP, same loopback), the same IPC namespace, and optionally the same PID namespace. Containers in a pod communicate over localhost.
You run multiple containers in a pod only when tight coupling is required. The canonical patterns are:
- Sidecar: a helper container that enhances the main container (e.g., Envoy proxy, log shipper like Fluent Bit).
- Init container: runs to completion before the main container starts (e.g., wait for a database to be ready, seed configuration).
- Ambassador: proxies outbound traffic from the main container to an external service.
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
initContainers:
- name: wait-for-db
image: busybox:1.35
command: ['sh', '-c', 'until nc -z db-service 5432; do sleep 2; done']
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
- name: log-forwarder
image: fluent/fluent-bit:2.1
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}What interviewers test: understanding of pod networking, and whether you know init containers are not sidecars (init containers terminate; sidecars run alongside the main process).
4. How do liveness and readiness probes differ? What happens if each fails?
A readiness probe gates traffic. If it fails, the pod is removed from the Endpoints list for its Service — new traffic stops being sent to it, but the pod keeps running. This is for "not ready to serve" situations: warming up a cache, loading a large model, waiting for a dependency.
A liveness probe gates restart. If it fails, the kubelet kills and restarts the container (subject to restartPolicy). This is for "stuck" situations: deadlocked goroutines, crashed-but-not-exited processes.
A startup probe is a third type: it delays liveness/readiness checks until the container passes startup. Critical for slow-starting apps to avoid premature liveness kills.
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 2
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10Common mistake: setting initialDelaySeconds too low for liveness probes, causing a restart loop on slow-starting apps. Use startup probes instead.
5. What are resource requests and limits? What happens when a container exceeds its memory limit?
Requests are what the scheduler uses for placement — it reserves that amount of CPU/memory on the node. Limits are the runtime enforcement ceiling.
- CPU: limits are enforced via CPU throttling (cgroups). The container is not killed; it is slowed.
- Memory: limits are enforced by the Linux OOM killer. If a container exceeds its memory limit, the kernel sends
SIGKILL(OOM kill), and Kubernetes restarts it.
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"A container without limits runs as Burstable or BestEffort class. BestEffort pods (no requests or limits) are the first to be evicted under node memory pressure.
What interviewers test: QoS classes (Guaranteed = requests equal limits; Burstable = requests set but not equal to limits; BestEffort = no requests or limits) and their eviction priority.
Deployments and ReplicaSets
6. What is the difference between a Deployment and a ReplicaSet?
A ReplicaSet ensures that a specified number of pod replicas are running at any time. It has no concept of rollouts or history.
A Deployment manages ReplicaSets. It provides declarative updates with rollout strategies (RollingUpdate, Recreate), rollback capability, and pause/resume. When you update a Deployment's pod template, it creates a new ReplicaSet and scales it up while scaling the old one down (for RollingUpdate).
You almost never create ReplicaSets directly. You create Deployments.
# Check rollout status
kubectl rollout status deployment/my-app
# View rollout history
kubectl rollout history deployment/my-app
# Roll back to previous version
kubectl rollout undo deployment/my-app
# Roll back to a specific revision
kubectl rollout undo deployment/my-app --to-revision=2What interviewers test: the layered abstraction. A Deployment is a controller for ReplicaSets, which is a controller for Pods.
7. How does a RollingUpdate strategy work? What do maxSurge and maxUnavailable control?
During a rolling update, Kubernetes incrementally replaces old pods with new ones.
maxUnavailable: how many pods can be unavailable at once (absolute number or percentage). Set to 0 to guarantee full capacity during the rollout — but this requiresmaxSurge > 0.maxSurge: how many pods above the desired replica count can temporarily exist. Allows spinning up new pods before killing old ones.
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
replicas: 4With replicas: 4, maxSurge: 1, maxUnavailable: 0: Kubernetes spins up 1 new pod (5 total), waits for it to pass readiness, then terminates 1 old pod (back to 4). Repeats until all pods are on the new version.
Common mistake: leaving both at the default (25%) without thinking about it. For latency-sensitive services, set maxUnavailable: 0.
8. How do you perform a canary deployment in Kubernetes without a service mesh?
A simple label-selector trick: have two Deployments with the same pod label that your Service selects on, but in different proportions.
# Service selects on app: my-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-stable
spec:
replicas: 9
selector:
matchLabels:
app: my-app
version: stable
template:
metadata:
labels:
app: my-app
version: stable
spec:
containers:
- name: app
image: myapp:1.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-canary
spec:
replicas: 1
selector:
matchLabels:
app: my-app
version: canary
template:
metadata:
labels:
app: my-app
version: canary
spec:
containers:
- name: app
image: myapp:1.1The Service selects app: my-app — 10% of traffic goes to the canary pod. Once validated, promote the canary to stable and scale down the old deployment.
For header-based or cookie-based canaries, you need an Ingress controller (like nginx) or a service mesh (Istio/Linkerd).
StatefulSets and DaemonSets
9. When do you use a StatefulSet instead of a Deployment?
Use a StatefulSet when pods need:
- 1Stable network identities: pods get predictable names (
app-0,app-1,app-2) and DNS entries (app-0.my-service.namespace.svc.cluster.local). - 2Stable persistent storage: each pod gets its own PersistentVolumeClaim that survives pod restarts and rescheduling.
- 3Ordered startup/shutdown: pods start in order (0 → 1 → 2) and terminate in reverse order.
Use cases: databases (Postgres, MySQL, Cassandra), message brokers (Kafka, ZooKeeper), Elasticsearch clusters.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10GiWhat interviewers test: understanding of why stateful workloads cannot use Deployments — pod identity must be stable across restarts because peers reference each other by hostname.
10. What is a DaemonSet and when would you use one?
A DaemonSet ensures that exactly one pod runs on every node (or every node matching a node selector). When nodes are added to the cluster, the DaemonSet controller automatically schedules a pod on them.
Use cases:
- Log collection agents (Fluent Bit, Filebeat) — need access to host log paths
- Metrics collection (node-exporter) — need host network metrics
- Security agents (Falco, Datadog agent) — need kernel-level access
- CNI plugins and kube-proxy themselves are often managed as DaemonSets
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
name: node-exporter
template:
metadata:
labels:
name: node-exporter
spec:
hostNetwork: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:v1.6.1
ports:
- containerPort: 9100
hostPort: 9100
securityContext:
privileged: trueCommon mistake: confusing DaemonSets with Deployments with replicas: N where N equals node count. A DaemonSet is node-aware; a Deployment is not.
Services and Networking
11. What are the four Service types and when do you use each?
- ClusterIP (default): exposes the service on a cluster-internal IP. Only reachable within the cluster. Use for inter-service communication.
- NodePort: exposes the service on every node's IP at a static port (30000–32767). Externally reachable but bypasses load balancing. Useful for development or baremetal clusters without a cloud load balancer.
- LoadBalancer: provisions an external load balancer in the cloud provider (AWS NLB/ALB, GCP LB, Azure LB). The standard way to expose services externally in cloud environments.
- ExternalName: maps the service to a DNS name (e.g.,
db.example.com). No proxying; returns a CNAME. Useful for pointing cluster services to external resources.
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080What interviewers test: why you would NOT use LoadBalancer for every service (cost: each LoadBalancer provisions a cloud resource). Use ClusterIP + Ingress for most HTTP workloads.
12. What is a headless service and why would you use it?
A headless service has clusterIP: None. Instead of returning a single virtual IP, DNS queries for the service return the individual pod IPs directly. This enables clients to do their own load balancing or to connect to specific pods by name.
StatefulSets require a headless service so that each pod gets a stable DNS record: pod-name.service-name.namespace.svc.cluster.local.
apiVersion: v1
kind: Service
metadata:
name: cassandra
spec:
clusterIP: None
selector:
app: cassandra
ports:
- port: 9042What interviewers test: the distinction between virtual-IP-based services (kube-proxy programs iptables rules) and headless services (pure DNS).
13. What is an Ingress and how does it differ from a Service?
A Service operates at Layer 4 (TCP/UDP) — it routes by IP and port. An Ingress operates at Layer 7 (HTTP/HTTPS) — it routes by hostname and path, terminates TLS, and can apply middleware (rate limiting, auth).
An Ingress object is just a configuration spec. It requires an Ingress controller (nginx-ingress, Traefik, Kong, AWS ALB controller) to actually implement the rules.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80What interviewers test: that you know Ingress needs a controller, and that you understand TLS termination at the Ingress level (not the pod level).
ConfigMaps and Secrets
14. How do you inject configuration into a pod? What are the tradeoffs between env vars and volume mounts?
Two mechanisms: environment variables and volume mounts.
Environment variables:
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secretsEnvironment variables are set at container start — a ConfigMap update does NOT propagate to running pods without a restart.
Volume mount:
volumes:
- name: config-vol
configMap:
name: app-config
volumeMounts:
- name: config-vol
mountPath: /etc/configVolume-mounted ConfigMaps are updated automatically (with a ~1 minute kubelet sync delay). Useful for apps that watch config files (nginx, feature flags).
Tradeoffs:
- Env vars: simpler, but immutable at runtime and leak through process inspection (
/proc/PID/environ) - Volumes: dynamic updates, but file path coupling and slightly more complex
What interviewers test: knowing the update semantics. Many engineers assume ConfigMap env vars hot-reload — they do not.
15. How are Secrets different from ConfigMaps? Are Secrets actually secure?
Functionally, Secrets are nearly identical to ConfigMaps — same injection mechanisms, same volume mount behavior. The differences:
- Secrets are base64-encoded (NOT encrypted by default) in etcd.
- Kubernetes marks them as sensitive: they are not shown in
kubectl describeby default, they are stored in tmpfs on nodes (not written to disk), and RBAC should restrict access.
Are they secure? Not by default. Anyone with kubectl get secret -n production RBAC access can base64-decode them. Real Secret security requires:
- 1etcd encryption at rest (EncryptionConfiguration with AES-GCM or KMS provider)
- 2External secret managers: AWS Secrets Manager + External Secrets Operator, HashiCorp Vault + Vault Agent Injector, or GCP Secret Manager.
- 3RBAC: least-privilege access to secrets per namespace.
# Create a secret imperatively (avoid storing in shell history)
kubectl create secret generic db-creds \
--from-literal=username=admin \
--from-literal=password='S3cur3P@ss'
# Inspect (base64 decode to see plaintext)
kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -dWhat interviewers test: that you know base64 is encoding, not encryption, and that you can describe a production-grade secrets management approach.
RBAC and Security
16. Explain Kubernetes RBAC. What are the four key objects?
RBAC (Role-Based Access Control) controls who can do what to which resources.
- Role: namespaced. Grants permissions within a namespace.
- ClusterRole: cluster-wide. Grants permissions across all namespaces or on non-namespaced resources (nodes, PersistentVolumes).
- RoleBinding: binds a Role or ClusterRole to subjects (users, groups, ServiceAccounts) within a namespace.
- ClusterRoleBinding: binds a ClusterRole to subjects cluster-wide.
# Role: allows reading pods in "staging" namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: staging
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
# Bind it to a ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: staging
subjects:
- kind: ServiceAccount
name: ci-runner
namespace: staging
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io# Test if a ServiceAccount can perform an action
kubectl auth can-i list pods --namespace=staging \
--as=system:serviceaccount:staging:ci-runnerWhat interviewers test: least-privilege principle, the difference between Role and ClusterRole, and whether you know kubectl auth can-i for debugging.
17. What is a PodSecurityContext and what security settings should you always configure?
securityContext at the pod or container level controls Linux security settings for the running process.
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALLKey settings for hardening:
runAsNonRoot: true— prevents running as root (UID 0)allowPrivilegeEscalation: false— preventssudoor SUID binariesreadOnlyRootFilesystem: true— forces write operations to explicit volumescapabilities: drop: ALL— removes all Linux capabilities (add back only what you need)seccompProfile: RuntimeDefault— restricts syscalls to a safe default profile
What interviewers test: whether you know Pod Security Admission (PSA) policies (Privileged, Baseline, Restricted) and that simply not running as root is not sufficient hardening.
18. What is a NetworkPolicy and how do you deny all traffic by default?
NetworkPolicies are firewall rules for pods. They require a CNI plugin that supports them (Calico, Cilium, Weave) — vanilla kubenet does not enforce them.
A default-deny policy:
# Deny all ingress and egress in the namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressThen explicitly allow what is needed:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432What interviewers test: understanding that NetworkPolicies are additive (empty policy = deny nothing; podSelector: {} + policyTypes: [Ingress] with no ingress rules = deny all ingress). And that without a supporting CNI, they are silently ignored.
Horizontal Pod Autoscaler
19. How does the HPA work? What metrics can it scale on?
The HPA controller queries the Metrics API every 15 seconds (default). Based on current versus target utilization, it calculates a new desired replica count:
desiredReplicas = ceil(currentReplicas × (currentMetric / desiredMetric))apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 400Mi
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"Metric sources (autoscaling/v2):
Resource: CPU and memory from metrics-serverPods: custom metrics per pod (via custom metrics API adapter)Object: metrics from a Kubernetes object (e.g., Ingress requests/second)External: metrics from outside the cluster (e.g., SQS queue depth via KEDA)
What interviewers test: the prerequisite (metrics-server must be installed), scale-down cooldown (5 minutes by default to avoid flapping), and the difference between HPA (pod count) and VPA (pod resource size).
20. What is the difference between HPA and VPA? Can you use them together?
HPA (Horizontal Pod Autoscaler): scales by adding/removing pod replicas. Best for stateless, horizontally-scalable workloads.
VPA (Vertical Pod Autoscaler): adjusts resource requests/limits of existing pods. Requires evicting and restarting pods to apply new resource values. Best for workloads that do not scale horizontally (single-instance databases, batch jobs).
Can you use them together? Partially. Never run HPA on CPU/memory and VPA simultaneously — they fight each other. You can run HPA on a custom metric (like requests/second) with VPA handling CPU/memory sizing.
# Check HPA status
kubectl get hpa -n production
kubectl describe hpa my-app-hpa -n production
# Common issue: HPA shows <unknown>/60% for CPU
# Root cause: missing metrics-server OR missing resource requests on podsPersistentVolumes
21. Explain the PV/PVC lifecycle. What is a StorageClass?
Three objects:
- PersistentVolume (PV): cluster-level resource representing actual storage (an NFS share, an EBS volume, a Ceph RBD). Created statically by admins or dynamically by a provisioner.
- PersistentVolumeClaim (PVC): namespace-level request for storage. Specifies size and access mode. Binds to a matching PV.
- StorageClass: defines a provisioner and parameters. Enables dynamic provisioning — when a PVC is created, the StorageClass provisions a PV automatically.
# StorageClass (admin creates once)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
# PVC (developer creates)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
# Pod using the PVC
volumes:
- name: data
persistentVolumeClaim:
claimName: app-dataAccess modes:
ReadWriteOnce (RWO): one node at a time (most block storage)ReadOnlyMany (ROX): many nodes, read-onlyReadWriteMany (RWX): many nodes, read-write (NFS, EFS, CephFS)
Reclaim policies:
Delete: PV and underlying storage are deleted when PVC is deleted (default for dynamic provisioning)Retain: PV is kept after PVC deletion; admin must manually clean upRecycle: deprecated
What interviewers test: that you understand WaitForFirstConsumer binding mode — it delays PV provisioning until a pod is scheduled, ensuring the volume is created in the same AZ as the pod.
Helm
22. What is Helm and what problem does it solve?
Helm is a package manager for Kubernetes. It bundles related Kubernetes manifests into a chart — a versioned, parameterizable unit. It solves:
- Templating: avoid duplicating YAML across environments with
{{ .Values.replicaCount }} - Versioning: charts have versions; releases can be rolled back
- Lifecycle management:
helm install,helm upgrade,helm rollback,helm uninstall
# Add a repo and install
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install my-postgres bitnami/postgresql \
--namespace db \
--set auth.postgresPassword=secret \
--set primary.persistence.size=50Gi
# Override with a values file (preferred over --set for production)
helm install my-postgres bitnami/postgresql \
--namespace db \
-f values-production.yaml
# Check deployed releases
helm list -A
# Upgrade
helm upgrade my-postgres bitnami/postgresql -f values-production.yaml
# Rollback to revision 1
helm rollback my-postgres 1What interviewers test: awareness of Helm's templating gotchas (whitespace handling, toYaml with indent), and the existence of helm template for rendering manifests locally to debug them.
23. What is the structure of a Helm chart?
my-chart/
├── Chart.yaml # Chart metadata (name, version, appVersion)
├── values.yaml # Default values (overridden by -f or --set)
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── _helpers.tpl # Named templates (partials)
│ └── NOTES.txt # Post-install instructions
├── charts/ # Subcharts (dependencies)
└── .helmignoreKey template functions:
# _helpers.tpl
{{- define "my-chart.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
# deployment.yaml
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}What interviewers test: whether you can debug a helm template output versus what is actually deployed (helm get manifest ), and how to use helm lint.
Troubleshooting
24. A pod is stuck in Pending. How do you diagnose it?
kubectl describe pod <pod-name> -n <namespace>Look at the Events section at the bottom. Common causes and their event messages:
| Event message | Root cause |
|---|---|
| 0/3 nodes are available: 3 Insufficient cpu | No node has enough CPU to satisfy the pod's request |
| 0/3 nodes are available: 3 node(s) had untolerated taint | Pod has no toleration for node taints |
| 0/3 nodes are available: 3 didn't match Pod's node affinity | nodeAffinity/nodeSelector rules exclude all nodes |
| persistentvolumeclaim "..." not found | PVC doesn't exist or is in wrong namespace |
| no persistent volumes available for this claim | No PV matches the PVC's storage class/access mode/size |
# Check node capacity
kubectl describe nodes | grep -A5 "Allocated resources"
# Check if PVC is bound
kubectl get pvc -n <namespace>
# Check available PVs
kubectl get pvWhat interviewers test: systematic diagnosis from events, not guessing. The answer to "it's pending" is always kubectl describe.
25. A pod is in CrashLoopBackOff. What is your diagnostic process?
CrashLoopBackOff means the container started, crashed, Kubernetes restarted it, it crashed again — and now Kubernetes is applying exponential backoff before retrying.
# Check current logs
kubectl logs <pod> -n <namespace>
# Check logs from the PREVIOUS (crashed) container instance — critical
kubectl logs <pod> -n <namespace> --previous
# Describe to see exit codes and restart count
kubectl describe pod <pod> -n <namespace>Exit codes that tell a story:
Exit Code 1: application error (check logs)Exit Code 137: OOM kill (SIGKILL) — check memory limits and usageExit Code 139: segfault (SIGSEGV)Exit Code 143: graceful shutdown (SIGTERM) — might be a liveness probe killing it
# If the container crashes immediately and you can't get logs:
# Override the entrypoint to keep it alive for inspection
kubectl debug -it <pod> --image=busybox --target=<container>
# Or patch the deployment to override command
kubectl set image deployment/my-app my-app=busybox
kubectl set env deployment/my-app -- sleep infinityWhat interviewers test: using --previous for logs (most people miss this), and systematic triage by exit code.
26. How do you exec into a running container? How do you copy files to/from it?
# Exec into a container
kubectl exec -it <pod> -n <namespace> -- /bin/bash
# If the pod has multiple containers, specify which one
kubectl exec -it <pod> -n <namespace> -c <container-name> -- /bin/sh
# Copy a file from a container to local machine
kubectl cp <namespace>/<pod>:/path/to/file ./local-file
# Copy from local to container
kubectl cp ./local-file <namespace>/<pod>:/path/to/file
# Run a one-off debugging pod with network tools
kubectl run debug-pod --rm -it \
--image=nicolaka/netshoot \
--restart=Never \
-- /bin/bashWhat interviewers test: knowing nicolaka/netshoot or similar Swiss Army knife images for network debugging (curl, dig, tcpdump, netstat, nmap all in one image).
27. How do you check why a node is NotReady?
# List nodes and their status
kubectl get nodes
# Describe the not-ready node
kubectl describe node <node-name>
# Look for conditions
kubectl get node <node-name> -o jsonpath='{.status.conditions[*].message}'
# Check kubelet logs on the node (requires SSH or node-level access)
journalctl -u kubelet -n 100 --no-pager
# Common causes:
# - kubelet crashed or stopped
# - Node is under memory/disk pressure (check conditions: MemoryPressure, DiskPressure)
# - Network issue: node can't reach the API server
# - containerd/docker daemon crashed
# Check node conditions programmatically
kubectl get nodes -o json | jq '.items[].status.conditions[] | select(.status=="True")'What interviewers test: whether you know the difference between a node being unreachable versus a node being evicted due to resource pressure, and the relevant node conditions to inspect.
28. How do you debug a Service that is not routing traffic to pods?
Methodical approach:
# Step 1: verify the service exists and has the right selector
kubectl describe service <service-name> -n <namespace>
# Look for: Selector, Endpoints
# Step 2: check if endpoints are populated
kubectl get endpoints <service-name> -n <namespace>
# If "Endpoints: <none>" — the selector does not match any running pods
# Step 3: verify pod labels match the service selector
kubectl get pods -n <namespace> --show-labels
# Compare pod labels with service's selector
# Step 4: check if pods pass readiness probes
kubectl get pods -n <namespace>
# Pods must be Running AND Ready (1/1, not 0/1)
# Step 5: test connectivity from inside the cluster
kubectl run test-pod --rm -it --image=curlimages/curl --restart=Never \
-- curl http://<service-name>.<namespace>.svc.cluster.local:<port>
# Step 6: check DNS resolution
kubectl run test-dns --rm -it --image=busybox --restart=Never \
-- nslookup <service-name>.<namespace>.svc.cluster.localCommon root cause: pod labels have a typo, or the pods exist but are not Ready because readiness probes fail — which means they are excluded from Endpoints.
Multi-Container Patterns
29. Explain the sidecar, ambassador, and adapter patterns with concrete examples.
Sidecar augments the main container without changing it:
- Envoy/Istio proxy intercepting all traffic for mTLS and observability
- Fluent Bit collecting and forwarding container logs to a centralized system
- A secret rotation sidecar writing new credentials to a shared volume
Ambassador proxies outbound connections from the main container:
- A sidecar container that accepts localhost connections and proxies them to the correct environment-specific endpoint (dev, staging, production) — the main app always connects to
localhost:5432 - A connection pooling proxy (PgBouncer) running as a sidecar so the main app doesn't manage connection pools
Adapter transforms output from the main container into a standard format:
- A sidecar that reads app-specific metrics in a custom format and exposes them as standard Prometheus metrics on
:9090/metrics - A log transformer that converts structured JSON logs into the format expected by a legacy log aggregator
containers:
- name: app
image: legacy-app:1.0
# writes logs in custom format to /var/log/app.log
- name: log-adapter
image: log-transformer:1.0
# reads /var/log/app.log, writes to stdout in JSON
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
emptyDir: {}30. How do init containers differ from regular containers? What are they used for?
Init containers run sequentially before any regular container starts. They must complete successfully (exit 0) before the next init container — or the main containers — start. If an init container fails, the pod is restarted according to restartPolicy.
They share volumes with main containers but have separate images and resource quotas.
Use cases:
- Database migration: run
alembic upgrade headorrails db:migratebefore the app starts - Dependency waiting:
until curl -sf http://redis:6379; do sleep 1; done - Secret seeding: pull secrets from Vault into a shared volume before the app reads them
- Permission setup:
chmod 700 /databefore a process that needs specific permissions starts
initContainers:
- name: run-migrations
image: myapp:1.0
command: ["python", "manage.py", "migrate", "--noinput"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
- name: wait-for-cache
image: redis:7-alpine
command: ['sh', '-c', 'until redis-cli -h redis ping; do sleep 2; done']What interviewers test: init containers are sequential and blocking — they enforce ordering without pod interdependency. Main containers start in parallel once all init containers complete.
Advanced Topics
31. What is a taint and toleration? How do they work together?
Taints are applied to nodes to repel pods that do not explicitly tolerate them. Tolerations are applied to pods to allow them to be scheduled on tainted nodes.
# Taint a node (no GPU workloads unless tolerated)
kubectl taint nodes node1 hardware=gpu:NoSchedule
# Remove the taint
kubectl taint nodes node1 hardware=gpu:NoSchedule-# Pod that tolerates the GPU taint
tolerations:
- key: "hardware"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"Taint effects:
NoSchedule: don't schedule new pods here (existing pods unaffected)PreferNoSchedule: prefer not to schedule here (soft)NoExecute: evict existing pods that don't tolerate this taint, don't schedule new ones
What interviewers test: the asymmetry — taints are on nodes, tolerations are on pods; tolerations allow scheduling on tainted nodes but do not force it (you still need nodeAffinity to force assignment to specific nodes).
32. What is the difference between nodeSelector, nodeAffinity, and podAffinity?
- nodeSelector: simplest form — requires exact label match on node. No OR conditions.
- nodeAffinity: more expressive. Supports
In,NotIn,Exists,DoesNotExist,Gt,Ltoperators. HasrequiredDuringSchedulingIgnoredDuringExecution(hard) andpreferredDuringSchedulingIgnoredDuringExecution(soft). - podAffinity/podAntiAffinity: schedule pods relative to other pods.
podAntiAffinityspreads pods across nodes/AZs.
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
- us-east-1b
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: my-app
topologyKey: kubernetes.io/hostnameThe podAntiAffinity with topologyKey: kubernetes.io/hostname ensures no two pods of the same app land on the same node — critical for HA deployments.
33. What is a PodDisruptionBudget (PDB) and why is it important?
A PDB limits the number of pods that can be voluntarily disrupted simultaneously — during node drains, cluster upgrades, or pod evictions by the autoscaler.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 2 # OR use maxUnavailable: 1
selector:
matchLabels:
app: my-appIf you have 3 replicas and minAvailable: 2, Kubernetes will not allow a kubectl drain or Cluster Autoscaler scale-down to remove more than 1 pod at a time. The drain will block until a pod is rescheduled elsewhere.
Common mistake: forgetting PDBs on stateless services. Without them, cluster upgrades drain all pods simultaneously, causing outages.
34. How does the Cluster Autoscaler work?
The Cluster Autoscaler (CA) watches for pods that cannot be scheduled due to resource constraints and requests new nodes from the cloud provider's autoscaling group. It also removes underutilized nodes (default: less than 50% utilized for 10+ minutes).
Scale-up: a pod is Pending → CA simulates whether any node group addition would allow scheduling → if yes, adds a node → cloud provider provisions it (1-3 min typically).
Scale-down: CA checks each node; if all its pods could be rescheduled elsewhere and it's been underutilized → CA drains and removes it (respects PDBs).
Important interactions:
- CA and HPA work together: HPA adds pods → CA adds nodes
- CA respects PDBs during scale-down
- Annotation
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"prevents CA from evicting a pod to shrink a node
35. What is etcd and why does it matter for cluster operations?
etcd is a distributed consensus key-value store (Raft protocol) that is the single source of truth for all cluster state: every API object, every secret, every lease. The API server is essentially a caching/validation layer over etcd.
For operations:
# Backup etcd (critical — do this before upgrades)
ETCDCTL_API=3 etcdctl snapshot save snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key
# Verify snapshot
etcdctl snapshot status snapshot.db
# Restore (after a catastrophic failure)
etcdctl snapshot restore snapshot.db \
--data-dir=/var/lib/etcd-restoredPerformance considerations: etcd is sensitive to disk I/O latency. IOPS spikes from colocated workloads corrupt leader election. Always run etcd on dedicated SSDs. For production clusters with 3+ control plane nodes, run a 3 or 5-node etcd cluster for HA.
36. How do you upgrade a Kubernetes cluster?
The safe upgrade path (control plane first, then nodes, one minor version at a time — no skipping):
# On control plane node
apt-get update && apt-get install -y kubeadm=1.28.0-00
# Check upgrade plan
kubeadm upgrade plan
# Apply upgrade
kubeadm upgrade apply v1.28.0
# Upgrade kubelet and kubectl on control plane
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
systemctl daemon-reload && systemctl restart kubelet
# For each worker node:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
# (on the worker node)
apt-get install -y kubeadm=1.28.0-00
kubeadm upgrade node
apt-get install -y kubelet=1.28.0-00
systemctl daemon-reload && systemctl restart kubelet
# (back on control plane)
kubectl uncordon <node-name>What interviewers test: the drain-upgrade-uncordon pattern per node, the need to upgrade kubeadm before kubelet, and the one-minor-version-at-a-time constraint.
37. What is a CRD and what is an Operator?
A Custom Resource Definition (CRD) extends the Kubernetes API with new resource types. Once created, you can kubectl get, kubectl apply, and interact with custom resources the same way you interact with built-in ones.
An Operator is a controller that watches custom resources and reconciles state. It encodes operational knowledge: how to deploy, scale, backup, and recover a specific application.
Examples: the Prometheus Operator (creates Prometheus, ServiceMonitor, PrometheusRule CRDs), the PostgreSQL Operator (Zalando's postgresql CRD that manages HA Postgres clusters), cert-manager (Certificate, Issuer CRDs for automatic TLS management).
# See all CRDs in the cluster
kubectl get crds
# Interact with a custom resource (cert-manager example)
kubectl get certificate -A
kubectl describe certificaterequest my-cert -n productionWhat interviewers test: that you understand Operators as an extension of the controller pattern — they are just controllers that happen to manage custom resources instead of built-in ones.
38. How do you implement zero-downtime deployments for a database-backed app?
Checklist for truly zero-downtime:
- 1Backward-compatible migrations: never drop a column in the same deploy as removing its usage. Use a two-phase process: deploy new code that works with both old and new schema → run migration → deploy cleanup.
- 2Readiness probes: ensure the pod is not added to Service Endpoints until it is truly ready (DB connections established, migrations checked, health endpoint returns 200).
- 3
maxUnavailable: 0in rolling update strategy.
- 4PodDisruptionBudget:
minAvailableequal to the minimum capacity needed to handle traffic.
- 5Graceful shutdown: handle
SIGTERM— stop accepting new requests, drain in-flight requests, close DB connections. SetterminationGracePeriodSecondsaccordingly.
- 6
preStoplifecycle hook (for apps that don't handle SIGTERM):
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]This 5-second sleep gives kube-proxy/Ingress time to remove the pod from the load balancer before the container receives SIGTERM.
39. What is a ServiceAccount token and how does pod-to-API server communication work?
By default, every pod gets a ServiceAccount token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. This token is a JWT that the pod uses to authenticate to the Kubernetes API server.
In Kubernetes 1.21+, these are bound service account tokens — short-lived (1 hour by default), audience-bound, and automatically rotated by the kubelet.
If your application uses the Kubernetes API (monitoring agents, operators, CI runners), it should use a ServiceAccount with minimal RBAC permissions:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-operator
namespace: operator-system
---
# Then bind it to the pod:
spec:
serviceAccountName: my-operator
automountServiceAccountToken: true # default; set false if unusedFor pods that don't need API access, set automountServiceAccountToken: false to avoid unnecessarily exposing credentials.
40. What are the key kubectl commands every engineer should know?
# Context management
kubectl config get-contexts
kubectl config use-context <context-name>
kubectl config set-context --current --namespace=<namespace>
# Rapid inspection
kubectl get all -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl top pods -n <namespace>
kubectl top nodes
# Editing live resources
kubectl edit deployment/<name>
kubectl patch deployment my-app -p '{"spec":{"replicas":5}}'
# Port-forwarding (without exposing via Service)
kubectl port-forward pod/<pod-name> 8080:8080
kubectl port-forward service/<service-name> 8080:80
# Debugging
kubectl debug node/<node-name> -it --image=ubuntu # privileged node access
kubectl get pod <pod> -o yaml # full spec including defaulted fields
kubectl explain deployment.spec.strategy # inline API docs
# Force delete a stuck terminating pod (last resort — can cause data issues)
kubectl delete pod <pod> --grace-period=0 --force
# Apply with dry-run to preview changes
kubectl apply -f manifest.yaml --dry-run=server
# Diff against live cluster
kubectl diff -f manifest.yamlQuick Reference: What Each Question Section Tests
| Topic | What interviewers really want to know |
|---|---|
| Architecture | Do you understand declarative reconciliation vs imperative commands? |
| Pods/Probes | Have you debugged crashed pods in production? |
| Deployments | Do you understand rollout mechanics, not just kubectl apply? |
| StatefulSets | Can you reason about pod identity and ordered operations? |
| Services/Ingress | Do you understand L4 vs L7, and the cost implications of LoadBalancer? |
| RBAC | Have you operated a multi-tenant cluster with real security requirements? |
| Secrets | Do you know the difference between encoding and encryption? |
| HPA/VPA | Can you design an autoscaling strategy for a real production workload? |
| PVs | Do you know access modes and what happens on node failure? |
| Helm | Have you managed releases across multiple environments? |
| Troubleshooting | Is your diagnostic process systematic or guess-based? |
| Advanced (taints, PDBs, etcd) | Are you ready for on-call on a production cluster? |
Final Preparation Advice
Set up a local cluster. Use kind (Kubernetes in Docker) or k3d for a full multi-node cluster on your laptop. Practice every command in this guide until it is muscle memory.
# Create a 3-node kind cluster
kind create cluster --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOFKnow your defaults. Interviewers ask about default values because defaults cause production incidents: default terminationGracePeriodSeconds (30s), default HPA cooldown (5 min scale-down), default ServiceAccount token automounting, default NetworkPolicy behavior (allow all).
Prepare a real incident story. Every interviewer will ask "tell me about a Kubernetes problem you debugged in production." Have a story ready with: symptoms, investigation steps (exactly which commands), root cause, and what you changed to prevent recurrence.
Practice kubectl without autocomplete. Interviewers watch whether you reach for docs or type confidently. Know the resource short names: po (pods), deploy (deployments), svc (services), cm (configmaps), pvc (persistentvolumeclaims), hpa (horizontalpodautoscalers), ns (namespaces).