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.
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.
# 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 containersMultiple 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.
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.
# 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.
# 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 volumeDocker ā Mid Level
Q6: How do you reduce Docker image size?
- Use minimal base images:
mcr.microsoft.com/dotnet/aspnet:9.0(~200 MB) vssdk(~800 MB). For non-.NET:alpinevariants. - Multi-stage builds: discard build artifacts.
.dockerignore: excludebin/,obj/,.git,tests/from build context.- Combine RUN commands: each
RUNcreates a layer. - Clean up in the same layer:
apt-get install && rm -rf /var/lib/apt/lists/*
# 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?
# Never hardcode secrets in Dockerfile
ENV SECRET_KEY=abc123 # WRONG ā baked into image, visible in history
# Correct: inject at runtime# 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.0For 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).
# 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:7Network 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?
# 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.dmpKubernetes ā 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.
# 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 onlyQ12: 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)
# 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# Reference in Pod spec
containers:
- name: myapp
envFrom:
- configMapRef:
name: myapp-config
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secrets
key: DATABASE_PASSWORDQ13: 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?
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 PodsK8s 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?
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?
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?
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: 400MiHPA 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?
- Readiness probe on
/health/readyā K8s removes Pod from load balancer when not ready maxUnavailable: 0in rolling update strategyterminationGracePeriodSecondslong enough for in-flight requests to completepreStophook to delay SIGTERM (gives load balancer time to stop routing):
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// 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:
- Sealed Secrets (Bitnami): encrypt secrets at rest with a cluster key ā safe to commit to git
- External Secrets Operator: sync from Azure Key Vault / AWS Secrets Manager / HashiCorp Vault into K8s Secrets
- Azure Workload Identity: Pods use Managed Identity to read Key Vault directly ā no secrets in K8s at all
# 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 nameQ20: 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:
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 PVCQ21: How do you debug a Pod that won't start?
# 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 failureEnjoyed this article?
Explore the Cloud & DevOps learning path for more.
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.