Interview Q&A All Levels Kubernetes

Kubernetes Interview Questions & Answers (2026) Part 02

25+ Kubernetes interview questions and answers covering pods, deployments, services, networking, scaling, debugging, and advanced scenarios — Basic to Advanced.

April 26, 2025 16 min read 60 Questions DB
Level:

Ans:

Kubernetes (K8s) is an open-source container orchestration platform that automates deployment, scaling, and management of containerized applications.

Why we need it:

  • Docker alone can’t: auto-restart failed containers, scale automatically, load-balance traffic, or do rolling updates
  • Kubernetes handles all of this and more

Core capabilities:

FeatureWhat it does
Self-healingAuto-restarts failed containers
Auto-scalingHPA scales pods based on CPU/memory
Load balancingDistributes traffic across pods
Rolling updatesZero-downtime deployments
Service discoveryPods find each other by name
Storage orchestrationDynamic PV provisioning
Secret managementSecure secret injection
# Check cluster info
kubectl cluster-info

# Get all nodes
kubectl get nodes

Ans:

Pod — Smallest deployable unit. Contains one or more containers that share network/storage.

# Basic pod
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: app
    image: nginx:1.25
    ports:
    - containerPort: 80

Deployment — Manages ReplicaSet + rolling updates + rollback for stateless apps.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: nginx:1.25

Service — Stable network endpoint for pods. Provides load balancing and service discovery.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

Ans:

ResourcePurposePod IdentityStorageUse Case
ReplicaSetMaintains N replicasRandom namesShared/noneRarely used directly
DeploymentManages RS + rolling updatesRandom names (pod-xxx)EphemeralStateless apps (APIs, web servers)
StatefulSetOrdered, stable pod namesStable (pod-0, pod-1)Per-pod PVCDatabases, Kafka, Zookeeper
# Deployment pods:
my-deploy-7d4f8b-abc12
my-deploy-7d4f8b-xyz99

# StatefulSet pods (ordered, stable):
my-db-0
my-db-1
my-db-2

StatefulSet guarantees:

  • Pods created in order (0, 1, 2…)
  • Deleted in reverse order (2, 1, 0)
  • Each pod gets its own PVC (data persists even if pod restarts)

Ans:

kubectl apply -f pod.yaml
         │
         ▼
API Server (validates, stores in etcd)
         │
         ▼
etcd (persists pod spec with no nodeName)
         │
         ▼
Scheduler (watches for unscheduled pods)
    1. Filtering: Removes nodes that can't run pod
       (insufficient CPU/memory, taints, node selector)
    2. Scoring: Ranks remaining nodes
       (least requested resources, affinity, topology)
    3. Binding: Sets pod.spec.nodeName = best node
         │
         ▼
Kubelet on selected node (watches API for pods assigned to it)
    1. Pulls container image (if not cached)
    2. Creates containers via container runtime (containerd)
    3. Starts containers
    4. Reports status back to API Server
         │
         ▼
Pod Running (status updated in etcd via API Server)
# Watch scheduling events
kubectl describe pod my-pod
kubectl get events --sort-by='.lastTimestamp'

Ans:

# Step 1: Check pod status and events
kubectl describe pod <pod-name> -n <namespace>
# Look at: Events section, Last State, Exit Code

# Step 2: Check logs (current and previous container)
kubectl logs <pod-name>
kubectl logs <pod-name> --previous    # Logs from crashed container

# Step 3: Check exit code
# Exit 0 = success (but CMD finished unexpectedly)
# Exit 1 = application error
# Exit 137 = OOMKilled
# Exit 139 = segfault

# Step 4: Get into the container temporarily
kubectl exec -it <pod-name> -- sh

# Step 5: If container exits too fast to exec, override CMD
kubectl run debug --image=myimage --command -- sleep 3600
kubectl exec -it debug -- sh

# Step 6: Check resource limits
kubectl describe pod <pod-name> | grep -A5 Limits

# Step 7: Check liveness probe config
kubectl describe pod <pod-name> | grep -A10 Liveness

# Common causes:
# - Wrong command/entrypoint
# - Missing env vars or config
# - OOMKilled (need more memory)
# - App crashes on startup
# - Liveness probe too aggressive

Ans:

Ingress is a Kubernetes resource that manages external HTTP/HTTPS access to services, providing routing, SSL termination, and name-based virtual hosting.

Internet → Ingress Controller (nginx/traefik) → Ingress Rules → Services → Pods

Ingress vs Service:

  • Service type: LoadBalancer = one cloud LB per service (expensive)
  • Ingress = one LB for all services with path/host routing
# Ingress resource example
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.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: 80
  tls:
  - hosts:
    - myapp.example.com
    secretName: tls-secret
# Install nginx ingress controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

# Check ingress
kubectl get ingress
kubectl describe ingress app-ingress

Ans:

# Step 1: Verify service exists and has correct port
kubectl get service my-service
kubectl describe service my-service

# Step 2: Check endpoints (are pods registered?)
kubectl get endpoints my-service
# If NO endpoints → selector mismatch or pods not Running

# Step 3: Verify pod labels match service selector
kubectl get pods --show-labels
kubectl describe service my-service | grep Selector
# Both must match!

# Step 4: Test from within the cluster (using a debug pod)
kubectl run test --image=busybox --rm -it -- sh
wget -O- http://my-service:80
nslookup my-service

# Step 5: Test DNS resolution
nslookup my-service.default.svc.cluster.local

# Step 6: Check pod is Running and ready
kubectl get pods -l app=myapp
# STATUS must be Running, READY must be 1/1

# Step 7: Check NetworkPolicies blocking traffic
kubectl get networkpolicies -n <namespace>
kubectl describe networkpolicy <policy-name>

# Step 8: Test directly to pod IP (bypass service)
POD_IP=$(kubectl get pod <pod-name> -o jsonpath='{.status.podIP}')
kubectl run test --image=busybox --rm -it -- wget -O- http://$POD_IP:8080

Ans:

ProbePurposeAction on failure
LivenessIs the container alive/healthy?Restarts the container
ReadinessIs the container ready to receive traffic?Removes from Service (stops sending traffic)
StartupIs the container done starting up?Delays liveness/readiness checks during slow starts
spec:
  containers:
  - name: app
    image: myapp
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 15    # Wait before first check
      periodSeconds: 10           # Check every 10s
      failureThreshold: 3         # Restart after 3 failures

    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
      failureThreshold: 3         # Remove from service after 3 failures

    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30        # Allow 5 minutes to start (30 * 10s)
      periodSeconds: 10

Ans:

HPA automatically scales the number of pods in a deployment based on CPU/memory/custom metrics.

HPA controller → queries metrics-server → compares with target
     │
     └── if CPU > threshold → increase replicas
     └── if CPU < threshold → decrease replicas (min replicas floor)
# HPA manifest
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70   # Scale if CPU > 70%
# Check HPA status
kubectl get hpa
kubectl describe hpa my-hpa

# Quick create via CLI
kubectl autoscale deployment my-deployment --cpu-percent=70 --min=2 --max=10

Ans:

# Step 1: Check HPA status
kubectl describe hpa my-hpa
# Look for: current metrics, conditions, events

# Step 2: Check if metrics-server is running
kubectl get pods -n kube-system | grep metrics-server
kubectl top pods    # If this fails → metrics-server issue

# Step 3: Check that pod has resource requests defined
kubectl describe pod <pod-name> | grep -A5 Requests
# HPA REQUIRES resource requests to calculate utilization %
# If requests not set → HPA can't calculate utilization → won't scale

# Step 4: Check if min/max replicas are hit
kubectl get hpa my-hpa
# If REPLICAS = MAXREPLICAS → HPA is at max, can't scale more

# Step 5: Check cooldown periods
# HPA has a stabilization window (default 5 min scale-down, 3 min scale-up)
# Check scaleUp.stabilizationWindowSeconds in HPA spec

# Step 6: Check API server for RBAC issues
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods

# Fix: Add resource requests to pod spec
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"

Ans:

kubeconfig is a YAML file (~/.kube/config by default) that stores cluster connection details, credentials, and contexts for kubectl.

# ~/.kube/config structure
apiVersion: v1
kind: Config
clusters:
- name: my-cluster
  cluster:
    server: https://my-k8s-api:6443
    certificate-authority-data: BASE64...
users:
- name: my-user
  user:
    client-certificate-data: BASE64...
    client-key-data: BASE64...
contexts:
- name: my-context
  context:
    cluster: my-cluster
    user: my-user
    namespace: default
current-context: my-context
# View current config
kubectl config view

# List contexts
kubectl config get-contexts

# Switch context
kubectl config use-context my-cluster

# Set default namespace
kubectl config set-context --current --namespace=production

# Merge multiple kubeconfigs
KUBECONFIG=~/.kube/config:~/.kube/cluster2-config kubectl config view --merge --flatten > ~/.kube/merged-config

Ans:

# Create secret
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password=mysecret

# Create from file
kubectl create secret generic tls-certs \
  --from-file=tls.crt=./cert.crt \
  --from-file=tls.key=./cert.key

# View (base64 encoded)
kubectl get secret db-secret -o yaml
echo "bXlzZWNyZXQ=" | base64 -d   # decode
# Use in pod - as environment variable
spec:
  containers:
  - name: app
    envFrom:
    - secretRef:
        name: db-secret

# Use as individual env var
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password

# Mount as file (more secure - not in process env)
    volumeMounts:
    - name: secret-vol
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-vol
    secret:
      secretName: db-secret

Production best practice: Use External Secrets Operator to sync from AWS Secrets Manager / Vault into K8s secrets.

Ans:

Using CSI Secrets Store Driver + Azure Key Vault Provider:

# Step 1: Install CSI driver
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver

# Step 2: Install Azure Key Vault provider
helm repo add csi-secrets-store-provider-azure https://azure.github.io/secrets-store-csi-driver-provider-azure/charts
helm install azure-csi csi-secrets-store-provider-azure/csi-secrets-store-provider-azure
# Step 3: Create SecretProviderClass
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-keyvault-secrets
spec:
  provider: azure
  parameters:
    vaultName: my-keyvault
    clientID: <managed-identity-client-id>
    tenantID: <azure-tenant-id>
    objects: |
      array:
        - |
          objectName: db-password
          objectType: secret

# Step 4: Mount in pod
spec:
  containers:
  - name: app
    volumeMounts:
    - name: secrets-store
      mountPath: /mnt/secrets-store
      readOnly: true
  volumes:
  - name: secrets-store
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: azure-keyvault-secrets

Ans:

# Method 1: Direct env in pod spec
spec:
  containers:
  - name: app
    env:
    - name: ENV
      value: "production"
    - name: LOG_LEVEL
      value: "info"

# Method 2: From ConfigMap
# Create ConfigMap:
# kubectl create configmap app-config --from-literal=LOG_LEVEL=info

    envFrom:
    - configMapRef:
        name: app-config

# Method 3: From Secret
    envFrom:
    - secretRef:
        name: db-secret

# Method 4: From field reference (downward API)
    env:
    - name: MY_POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: MY_POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: MY_NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName

Ans:

NamespacePurpose
defaultWhere resources go if no namespace is specified
kube-systemKubernetes system components (CoreDNS, kube-proxy, metrics-server, etc.)
kube-publicPublicly accessible data, readable by all users
kube-node-leaseNode heartbeat leases for leader election
# List all namespaces
kubectl get namespaces

# View resources in kube-system
kubectl get pods -n kube-system

# Create a namespace
kubectl create namespace staging

# Set default namespace for your context
kubectl config set-context --current --namespace=staging

Ans:

TypeAccessUse Case
ClusterIPOnly inside clusterInternal service-to-service communication
NodePort<NodeIP>:<30000-32767> from outsideDevelopment/testing
LoadBalancerCloud LB public IPProduction external access
ExternalNameDNS CNAME aliasPoint to external DNS
# ClusterIP (default)
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080

# NodePort
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080    # Optional, auto-assigned if omitted

# LoadBalancer (creates cloud LB)
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
kubectl get service my-service
# EXTERNAL-IP column shows: <none> for ClusterIP, node IPs for NodePort, real IP for LB

Ans:

The default NodePort range is 30000–32767.

# Check configured range on API server
kube-apiserver --help | grep node-port-range
# or check /etc/kubernetes/manifests/kube-apiserver.yaml
grep -i nodeport /etc/kubernetes/manifests/kube-apiserver.yaml

# Custom range (set in kube-apiserver startup args):
--service-node-port-range=30000-32767

If you try to assign a port outside this range, the API server will reject it.

Ans:

Secrets — Kubernetes objects that store sensitive data like passwords, API tokens, TLS certificates.

Types of secrets:

  • Opaque — Generic key-value data (most common)
  • kubernetes.io/service-account-token — Service account JWT tokens
  • kubernetes.io/tls — TLS certificate and key
  • kubernetes.io/dockerconfigjson — Docker registry credentials
# List secrets
kubectl get secrets

# Create opaque secret
kubectl create secret generic my-secret \
  --from-literal=token=abc123

# Create docker registry secret
kubectl create secret docker-registry regcred \
  --docker-server=docker.io \
  --docker-username=myuser \
  --docker-password=mypass

# View secret (base64 encoded)
kubectl get secret my-secret -o jsonpath='{.data.token}' | base64 -d

Note: K8s Secrets are base64-encoded, NOT encrypted by default. Use etcd encryption at rest + Vault/AWS Secrets Manager for production.

Ans:

# Method 1: Rolling Update (default)
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0      # Never have 0 available pods
      maxSurge: 1            # Allow 1 extra pod during update

# Method 2: Add readiness probes (critical!)
  containers:
  - name: app
    readinessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 5
# K8s only routes traffic to pods that pass readiness probe
# Perform rolling update
kubectl set image deployment/my-deploy app=myimage:2.0

# Monitor rollout
kubectl rollout status deployment/my-deploy

# Rollback if issues
kubectl rollout undo deployment/my-deploy

# Method 3: Blue/Green deployment
# Deploy new version as separate deployment
# Switch service selector from app: blue → app: green

# Method 4: Canary with Ingress annotations
# Route 10% traffic to canary, 90% to stable
# nginx.ingress.kubernetes.io/canary: "true"
# nginx.ingress.kubernetes.io/canary-weight: "10"

Also use PodDisruptionBudget to prevent too many pods being unavailable:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-pdb
spec:
  minAvailable: 2    # Always keep at least 2 pods
  selector:
    matchLabels:
      app: myapp

Ans:

# Default deny all ingress in 'production' namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: production
spec:
  podSelector: {}     # Applies to all pods
  policyTypes:
  - Ingress
  - Egress
---
# Allow specific namespace to reach production
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-staging
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: staging
    ports:
    - port: 8080
# Apply the policy
kubectl apply -f netpol.yaml

# Test: pod in staging can reach production
kubectl exec -it <staging-pod> -- curl http://myapp.production:8080

# Test: pod in default namespace cannot reach production
kubectl exec -it <default-pod> -- curl http://myapp.production:8080
# Should fail/timeout

Note: NetworkPolicy requires a CNI plugin that supports it (Calico, Cilium, Weave). Flannel alone does NOT enforce NetworkPolicies.

Ans:

# Step 1: Immediately roll back (fastest)
kubectl rollout undo deployment/my-deployment -n production

# Step 2: Verify rollback is in progress
kubectl rollout status deployment/my-deployment -n production

# Step 3: Confirm old pods are running
kubectl get pods -n production

# Step 4: Check rollout history
kubectl rollout history deployment/my-deployment

# Step 5: Roll back to a specific revision
kubectl rollout undo deployment/my-deployment --to-revision=3

# Step 6: If rollback is slow, force a faster restart
kubectl rollout restart deployment/my-deployment

# Step 7: Verify application is responding
kubectl get svc my-service
curl http://<service-ip>/health

# Prevention for next time:
# - Set minReadySeconds to delay traffic routing
# - Use readiness probes
# - Use PodDisruptionBudget
# - Add deployment annotation: kubernetes.io/change-cause: "version 2.1 - added feature X"

Ans:

Most common causes:

# Cause 1: Using 'latest' tag (most common)
# K8s only pulls 'latest' if imagePullPolicy: Always
# Fix: Always use specific version tags
image: myapp:v1.2.3   # Never: myapp:latest in production

# Cause 2: imagePullPolicy not set correctly
# Default behavior:
# - :latest tag → Always pull
# - other tags → IfNotPresent (uses cached image!)
spec:
  containers:
  - name: app
    image: myapp:v1.2.3
    imagePullPolicy: Always   # Force pull on every start

# Cause 3: Image not pushed to registry before deploy
# Ensure CI pipeline order:
# 1. docker build
# 2. docker push ← must complete before step 3
# 3. kubectl set image

# Cause 4: Wrong image name/tag in deployment
kubectl describe deployment my-deployment | grep Image

# Cause 5: Old ReplicaSet running (deployment not updated)
kubectl get replicasets
kubectl rollout status deployment/my-deployment

# Cause 6: Cached image on node — delete pod to force fresh pull
kubectl delete pod <pod-name>   # New pod will pull fresh
# Or: kubectl rollout restart deployment/my-deployment

Ans:

# Step 1: Describe the pending pod for reasons
kubectl describe pod <pod-name>
# Look in Events section for: Insufficient cpu, Insufficient memory, 
# node(s) had untolerated taint, no matching node selector

# Step 2: Check node resources
kubectl describe nodes
kubectl top nodes   # Requires metrics-server

# Step 3: Check if nodes joined correctly
kubectl get nodes
# STATUS must be Ready

# Step 4: Check node labels (if using nodeSelector)
kubectl get node <node-name> --show-labels
kubectl describe pod <pod-name> | grep "Node-Selectors"

# Step 5: Check taints (new nodes may have taints)
kubectl describe node <node-name> | grep -i taint
# If node has taint: node.kubernetes.io/not-ready → node still initializing

# Step 6: Check for missing tolerations in pod spec
kubectl describe pod <pod-name> | grep -i toleration

# Step 7: EKS-specific: Check node group IAM role permissions
# Node needs: AmazonEKSWorkerNodePolicy, AmazonEC2ContainerRegistryReadOnly

# Step 8: Check if EKS add-ons are healthy (VPC CNI, kube-proxy, CoreDNS)
kubectl get pods -n kube-system

# Step 9: Check if PVC is Pending (if pod requires PVC)
kubectl get pvc
# StorageClass must exist and dynamic provisioning must work

Ans:

If an InitContainer fails and the Pod’s restartPolicy is Never, the pod fails permanently — it enters Failed state and is NOT restarted.

# Example
spec:
  restartPolicy: Never
  initContainers:
  - name: init-db
    image: busybox
    command: ['sh', '-c', 'exit 1']   # Always fails
  containers:
  - name: app
    image: myapp
# Pod will show:
kubectl get pod my-pod
# STATUS: Init:Error → then → Failed

# Debug
kubectl describe pod my-pod
kubectl logs my-pod -c init-db

# With restartPolicy: OnFailure or Always:
# Pod would retry the initContainer

Key rules:

  • InitContainers must all succeed before the main containers start
  • They run sequentially (one at a time)
  • If restartPolicy: Always → pod retries (CrashLoopBackOff after repeated failures)
  • If restartPolicy: Never → pod fails permanently on first failure

Ans:

A DaemonSet ensures one pod runs on every node (or a subset of nodes). Used for: log collectors (Fluentd), monitoring agents (Prometheus Node Exporter), network plugins.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      containers:
      - name: fluentd
        image: fluentd:latest

DaemonSet and master taints:

Yes — DaemonSets automatically add tolerations for:

  • node.kubernetes.io/not-ready
  • node.kubernetes.io/unschedulable
  • node-role.kubernetes.io/control-plane:NoSchedule
  • node-role.kubernetes.io/master:NoSchedule

This means DaemonSet pods CAN run on control-plane nodes by default, unlike regular pods.

kubectl get daemonset -n kube-system
# kube-proxy, calico-node etc. run on all nodes including masters

Add More Questions to This Guide

Know questions that should be here? Share them and help the community!

Open Google Form