Learnixo
Back to blog
Cloud & DevOpsintermediate

Docker & Kubernetes Interview Questions — Junior to Senior

80 Docker and Kubernetes interview questions with detailed answers: containers, images, Dockerfile best practices, Kubernetes objects, scaling, networking, security, and production patterns for .NET developers.

Asma Hafeez KhanMay 26, 202612 min read
DockerKubernetesDevOpsContainersInterviewK8s.NET
Share:š•

Docker & Kubernetes Interview Questions — Junior to Senior


Docker — Junior Level

Q1: What is a container and how does it differ from a virtual machine?

A container is a process running in an isolated environment on the host OS kernel. A VM runs a full guest OS.

| | Container | VM | |---|---|---| | Boot time | Milliseconds | Minutes | | Size | Megabytes | Gigabytes | | Kernel | Shares host kernel | Own kernel | | Isolation | Process/namespace | Full hardware virtualisation | | Density | Thousands per host | Tens per host |

Containers use Linux namespaces (PID, network, mount, UTS, IPC) for isolation and cgroups for resource limits. On Windows, Docker runs containers in a Linux VM (WSL2 or Hyper-V).


Q2: What is the difference between a Docker image and a container?

  • Image: read-only template — a layered filesystem built from a Dockerfile. Immutable.
  • Container: a running instance of an image — adds a writable layer on top.
Bash
# Image: static artifact
docker build -t myapp:1.0 .
docker images  # lists images

# Container: running process
docker run -d -p 8080:80 myapp:1.0
docker ps      # lists running containers

Multiple containers can run from the same image simultaneously. Each has its own writable layer, but they share the read-only image layers — efficient disk use.


Q3: Explain Docker image layers.

Each instruction in a Dockerfile creates a new layer. Layers are cached and shared between images.

DOCKERFILE
FROM mcr.microsoft.com/dotnet/aspnet:9.0      # base layer (shared)
WORKDIR /app                                   # layer 2
COPY --from=build /app/publish .              # layer 3 (your app)
ENTRYPOINT ["dotnet", "MyApp.dll"]            # metadata (no new layer)

If only your app code changes, Docker reuses all previous layers from cache — only layer 3 rebuilds. This makes builds fast. Order matters: put infrequently changing layers (base image, dependencies) before frequently changing layers (app code).


Q4: What is a multi-stage Dockerfile and why use it?

Multi-stage builds use multiple FROM statements. Intermediate stages are discarded — only the final image ships.

DOCKERFILE
# Stage 1: build (SDK image ~800 MB)
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish --no-restore

# Stage 2: runtime (ASP.NET runtime ~200 MB, not SDK)
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
WORKDIR /app
COPY --from=build /app/publish .

# Non-root user for security
RUN adduser --disabled-password --gecos "" appuser
USER appuser

EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

Final image is ~200 MB (runtime only), not ~800 MB (SDK). No build tools, no source code in the production image.


Q5: How do you persist data in Docker?

Containers are ephemeral — their writable layer is destroyed when the container is removed. For persistent data:

  • Named volumes (docker volume create): managed by Docker, persisted independently of containers. Best for databases.
  • Bind mounts: map a host directory into a container. Good for development (live reload).
  • tmpfs mounts: in-memory, not persisted. Good for sensitive temp files.
YAML
# docker-compose.yml
services:
  postgres:
    image: postgres:16
    volumes:
      - postgres_data:/var/lib/postgresql/data  # named volume

  api:
    image: myapp:1.0
    volumes:
      - ./src:/app/src  # bind mount for dev hot-reload

volumes:
  postgres_data:  # declare named volume

Docker — Mid Level

Q6: How do you reduce Docker image size?

  1. Use minimal base images: mcr.microsoft.com/dotnet/aspnet:9.0 (~200 MB) vs sdk (~800 MB). For non-.NET: alpine variants.
  2. Multi-stage builds: discard build artifacts.
  3. .dockerignore: exclude bin/, obj/, .git, tests/ from build context.
  4. Combine RUN commands: each RUN creates a layer.
  5. Clean up in the same layer: apt-get install && rm -rf /var/lib/apt/lists/*
DOCKERFILE
# Bad: two layers, cache not cleaned
RUN apt-get update
RUN apt-get install -y curl && rm -rf /var/lib/apt/lists/*

# Good: one layer, cleanup in same RUN
RUN apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/*

Q7: How do you handle environment-specific configuration in Docker?

DOCKERFILE
# Never hardcode secrets in Dockerfile
ENV SECRET_KEY=abc123  # WRONG — baked into image, visible in history

# Correct: inject at runtime
Bash
# Pass at runtime — not stored in image
docker run -e DATABASE_URL="postgresql://..." myapp:1.0

# Or from a file (never commit this file)
docker run --env-file .env myapp:1.0

For production, use Docker secrets (Swarm), Kubernetes secrets, or Azure Key Vault — never environment variables for secrets in multi-tenant environments (they're visible in docker inspect).


Q8: How does Docker networking work?

Docker creates network namespaces. Containers on the same network can communicate by container name (DNS resolution).

YAML
# docker-compose.yml — services share a default network
services:
  api:
    image: myapp:1.0
    # Can reach postgres by hostname "postgres" — no IP needed

  postgres:
    image: postgres:16

  redis:
    image: redis:7

Network types:

  • bridge (default): containers on same host, isolated from host network
  • host: container shares host network stack (Linux only, best performance)
  • none: no networking
  • overlay: multi-host networking (Docker Swarm / Kubernetes)

Q9: How do you debug a running container?

Bash
# Shell into a running container
docker exec -it my-container /bin/bash
# or for minimal images (no bash):
docker exec -it my-container /bin/sh

# View logs (follow with -f)
docker logs -f my-container --tail 100

# Inspect resource usage
docker stats my-container

# Inspect container metadata, environment, network
docker inspect my-container

# Copy files out of container
docker cp my-container:/app/logs/app.log ./local-logs/

# For .NET: attach dotnet-dump to running container
docker exec my-container dotnet-dump collect -p 1 -o /tmp/dump.dmp
docker cp my-container:/tmp/dump.dmp ./dump.dmp

Kubernetes — Junior Level

Q10: What is Kubernetes and what problems does it solve?

Kubernetes (K8s) is a container orchestration platform. It solves:

  • Scheduling: deciding which node runs which container
  • Self-healing: restarting crashed containers, replacing unhealthy nodes
  • Scaling: adding/removing replicas based on load
  • Service discovery: routing traffic to healthy pods by service name
  • Rolling updates: zero-downtime deployments with rollback
  • Config/secrets management: injecting config without baking it into images

Q11: What is the difference between a Pod, Deployment, and Service?

  • Pod: smallest deployable unit — one or more containers that share network and storage. Ephemeral (gets a new IP on restart).
  • Deployment: manages a set of identical Pods. Handles rolling updates, scaling, and self-healing.
  • Service: stable network endpoint that routes to a set of Pods via label selector. Gives a fixed DNS name and virtual IP regardless of which Pods are behind it.
YAML
# Deployment: declares desired state
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - containerPort: 8080

---
# Service: stable endpoint
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  selector:
    app: myapp       # routes to Pods with this label
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP    # internal only

Q12: What is a ConfigMap and Secret? When do you use each?

  • ConfigMap: non-sensitive configuration (connection timeout, feature flags, log level)
  • Secret: sensitive data (passwords, API keys, TLS certs) — base64-encoded at rest, but not encrypted by default (use KMS envelope encryption in production)
YAML
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  LOG_LEVEL: "Information"
  MAX_RETRIES: "3"

---
# Secret (base64 encoded — not encrypted!)
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
type: Opaque
data:
  DATABASE_PASSWORD: cGFzc3dvcmQ=  # base64("password") — never commit real values
YAML
# Reference in Pod spec
containers:
- name: myapp
  envFrom:
  - configMapRef:
      name: myapp-config
  env:
  - name: DATABASE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: myapp-secrets
        key: DATABASE_PASSWORD

Q13: What is the difference between ClusterIP, NodePort, and LoadBalancer service types?

| Type | Accessible from | Use case | |---|---|---| | ClusterIP | Inside cluster only | Internal service-to-service communication | | NodePort | Outside cluster via NodeIP:NodePort | Dev/testing only — exposes a port on every node | | LoadBalancer | Outside via cloud load balancer | Production external traffic (creates an Azure LB, AWS ELB, etc.) |

Use Ingress (not LoadBalancer per service) for HTTP/HTTPS routing in production — one load balancer, multiple services routed by host/path rules.


Kubernetes — Mid Level

Q14: How does a rolling update work in Kubernetes?

YAML
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # allow 1 extra Pod during update (4 total for 3 replicas)
      maxUnavailable: 0  # never reduce below 3 running Pods

K8s creates new Pods with the new image, waits for them to be Ready (pass liveness/readiness probes), then terminates old Pods. With maxUnavailable: 0, there's always replicas healthy Pods serving traffic.

Rollback: kubectl rollout undo deployment/myapp


Q15: What are liveness, readiness, and startup probes?

YAML
containers:
- name: myapp
  livenessProbe:
    # Restart the container if this fails
    httpGet:
      path: /health/live
      port: 8080
    initialDelaySeconds: 10
    periodSeconds: 15
    failureThreshold: 3

  readinessProbe:
    # Remove Pod from Service endpoints if this fails (stop sending traffic)
    httpGet:
      path: /health/ready
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 10

  startupProbe:
    # Replaces liveness during slow startup (e.g. .NET cold start)
    httpGet:
      path: /health/live
      port: 8080
    failureThreshold: 30   # 30 * 10s = 5 min to start
    periodSeconds: 10
  • Liveness: "is the container healthy?" — restart if not
  • Readiness: "is the container ready to serve traffic?" — remove from load balancer if not
  • Startup: "has the container finished starting?" — prevents liveness from killing slow-starting containers

Q16: How do you set resource requests and limits?

YAML
containers:
- name: myapp
  resources:
    requests:          # minimum guaranteed resources (used for scheduling)
      memory: "256Mi"
      cpu: "250m"      # 250 millicores = 0.25 CPU
    limits:            # maximum allowed (throttle CPU, OOMKill for memory)
      memory: "512Mi"
      cpu: "500m"
  • Request: what K8s guarantees. Pod is only scheduled on a node with enough capacity.
  • Limit: hard cap. Exceeding memory limit = OOMKilled. Exceeding CPU limit = throttled (not killed).
  • Always set both. Without limits, a runaway process can starve other Pods.

Q17: What is a Horizontal Pod Autoscaler?

YAML
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # scale up when avg CPU > 70%
  - type: Resource
    resource:
      name: memory
      target:
        type: AverageValue
        averageValue: 400Mi

HPA checks metrics every 15 seconds (default). Scale-up is faster than scale-down (cool-down window prevents flapping).


Kubernetes — Senior Level

Q18: How do you implement zero-downtime deployments for a .NET API?

  1. Readiness probe on /health/ready — K8s removes Pod from load balancer when not ready
  2. maxUnavailable: 0 in rolling update strategy
  3. terminationGracePeriodSeconds long enough for in-flight requests to complete
  4. preStop hook to delay SIGTERM (gives load balancer time to stop routing):
YAML
containers:
- name: myapp
  lifecycle:
    preStop:
      exec:
        command: ["/bin/sh", "-c", "sleep 5"]  # wait for LB health check to propagate
  terminationGracePeriodSeconds: 30

# In .NET: handle graceful shutdown
# The app receives SIGTERM; ASP.NET Core completes in-flight requests
# then shuts down within terminationGracePeriodSeconds
C#
// Program.cs — configure graceful shutdown timeout
builder.Services.Configure<HostOptions>(options =>
{
    options.ShutdownTimeout = TimeSpan.FromSeconds(25);
});

Q19: How do you manage secrets securely in Kubernetes?

Built-in K8s Secrets are base64-encoded, not encrypted. Options for production:

  1. Sealed Secrets (Bitnami): encrypt secrets at rest with a cluster key — safe to commit to git
  2. External Secrets Operator: sync from Azure Key Vault / AWS Secrets Manager / HashiCorp Vault into K8s Secrets
  3. Azure Workload Identity: Pods use Managed Identity to read Key Vault directly — no secrets in K8s at all
YAML
# External Secrets Operator pulling from Azure Key Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-secrets
spec:
  secretStoreRef:
    name: azure-keyvault-store
    kind: SecretStore
  target:
    name: myapp-secrets        # creates K8s Secret with this name
  data:
  - secretKey: DATABASE_PASSWORD
    remoteRef:
      key: myapp-db-password   # Key Vault secret name

Q20: What is the difference between a Deployment, StatefulSet, and DaemonSet?

| | Deployment | StatefulSet | DaemonSet | |---|---|---|---| | Pod identity | Interchangeable | Stable (pod-0, pod-1) | One per node | | Storage | Shared or none | Per-Pod PVC | Per-node | | Use case | Stateless APIs | Databases, Kafka | Log agents, monitoring | | Scaling | Any order | Ordered start/stop | Tracks node count |

StatefulSet example — PostgreSQL replica:

YAML
kind: StatefulSet
spec:
  serviceName: postgres  # headless service for stable DNS: postgres-0.postgres.default.svc
  replicas: 3
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      resources:
        requests:
          storage: 50Gi  # each Pod gets its own 50Gi PVC

Q21: How do you debug a Pod that won't start?

Bash
# 1. Check Pod status
kubectl get pods -n my-namespace
# Look for: Pending, CrashLoopBackOff, ImagePullBackOff, OOMKilled

# 2. Describe the Pod — shows events, scheduling failures, probe failures
kubectl describe pod my-pod-abc123 -n my-namespace

# 3. Check logs
kubectl logs my-pod-abc123 -n my-namespace
kubectl logs my-pod-abc123 -n my-namespace --previous  # previous container (if crashed)

# 4. For Pending: check node resources
kubectl describe nodes | grep -A5 "Allocated resources"

# 5. For CrashLoopBackOff: shell in with a debug container
kubectl debug -it my-pod-abc123 --image=busybox --target=myapp

# 6. For ImagePullBackOff: check secret
kubectl describe pod my-pod-abc123 | grep "Failed to pull"
# Usually: wrong image tag, missing imagePullSecret, registry auth failure

Enjoyed this article?

Explore the Cloud & DevOps learning path for more.

Found this helpful?

Share:š•

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.