Kubernetes problems become much more interesting when you are running Java and Spring Boot applications in production.
A Pod restarts unexpectedly. CPU suddenly reaches 95%. Memory keeps increasing. A health check starts failing. An application works perfectly on a developer laptop but crashes after deployment to Kubernetes.
At senior level, Kubernetes interviews are not just about remembering commands. Interviewers want to know whether you can find the real root cause of a production problem.
When a Java application is running inside Kubernetes, you need to understand both sides of the system:
This guide covers 40 senior-level Kubernetes troubleshooting interview questions specifically from a Java and Spring Boot developer's perspective.
If you are preparing for a senior Java, Spring Boot, Microservices, DevOps, AWS, or Cloud Native interview, these scenarios are worth understanding rather than simply memorizing.
CrashLoopBackOff means Kubernetes is repeatedly restarting a container that keeps failing.
I would start by checking the Pod status and events, followed by the container logs.
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous
The --previous option is particularly useful when the container has already restarted.
For a Spring Boot application, I would look for configuration errors, database connection failures, missing environment variables, startup exceptions, incorrect JVM options, and memory-related failures.
Senior-level approach: Don't just restart the Pod. Find out why the process is exiting.
A Pending Pod has not successfully started running on a node.
I would check:
kubectl describe pod <pod-name>
kubectl get nodes
kubectl describe nodes
A common mistake is to immediately investigate the Java application. If the container hasn't started, the problem may be entirely related to Kubernetes scheduling.
First determine whether the application is crashing or Kubernetes is killing the container.
Check:
kubectl get pod <pod-name> -o wide
kubectl describe pod <pod-name>
kubectl logs <pod-name> --previous
The important question is who caused the restart? The JVM, the application, the health probe, or Kubernetes itself?
OOMKilled means the container was terminated because it exceeded its memory limit or the node experienced memory pressure that resulted in the container being killed.
For Java applications, this is particularly important because Kubernetes memory limits and JVM heap sizing are related.
Increasing the Java heap without considering the container's total memory usage can make the situation worse.
First determine whether the JVM heap is actually the problem or whether the container is consuming memory outside the Java heap.
Investigate:
Useful tools include Java Flight Recorder, jcmd, heap dumps, JVM metrics, and container-level metrics.
The key point is that container memory is not exactly the same thing as Java heap memory.
The JVM runs inside the memory boundary imposed by the container.
If the container has a memory limit that is too close to the JVM's maximum heap, there may not be enough memory for other JVM and native components.
Java applications also consume memory through thread stacks, metaspace, code cache, direct memory, and other native allocations.
Therefore, heap sizing should leave sufficient headroom within the container's memory limit.
Start by determining whether the CPU is being consumed by application threads or by garbage collection.
Check:
Tools such as jstack, jcmd, Java Flight Recorder, and profiling tools can help identify CPU-intensive code.
Unlike memory, exceeding a CPU limit does not normally cause the container to be killed simply because it consumed more CPU.
Instead, CPU usage can be throttled.
For a latency-sensitive Java application, excessive CPU throttling can increase response times and reduce throughput.
CPU throttling occurs when a container is restricted from consuming CPU beyond its configured limit.
If a Spring Boot application becomes CPU-bound and is heavily throttled, requests may take longer to execute.
This can create a chain reaction:
CPU throttling → higher latency → more concurrent requests → more resource usage → even higher latency
Therefore, CPU metrics should be considered together with application latency and throughput.
Compare application-level and infrastructure-level telemetry.
For example:
If the JVM is spending most of its time in GC, investigate the JVM.
If CPU throttling is high while the JVM itself appears healthy, investigate Kubernetes resource configuration.
Readiness Probe: Determines whether the Pod is ready to receive traffic.
Liveness Probe: Determines whether the application is alive enough to remain running.
A readiness failure should normally remove the Pod from traffic without necessarily restarting it.
A liveness failure can cause Kubernetes to restart the container.
If the readiness probe fails incorrectly, Kubernetes can remove a healthy Pod from the Service endpoints.
If many Pods fail readiness at the same time, available capacity can drop dramatically.
For Spring Boot applications, health endpoints should be configured carefully so that readiness represents whether the application can actually handle traffic.
A liveness probe that is too aggressive can restart a healthy application during temporary CPU spikes, slow startup, or garbage collection pauses.
This can create:
Slow application → probe timeout → restart → startup load → probe timeout → restart
This is why liveness probes should not be treated as generic availability checks.
First determine which probe is failing and why.
Check:
Then manually test the health endpoint from inside the container if appropriate.
Java applications can take significant time to start because of class loading, dependency initialization, database connections, migrations, cache initialization, or other startup tasks.
A startup probe gives the application time to initialize before normal liveness and readiness checks become the main concern.
This can prevent Kubernetes from incorrectly restarting a slow-starting application.
Common causes include:
The first places I would look are application logs and Pod events.
Verify the Deployment configuration and inspect the running Pod.
kubectl describe pod <pod-name>
kubectl exec -it <pod-name> -- env
Check whether the variable comes from:
Also verify that the expected key actually exists.
A ConfigMap is commonly used for non-sensitive configuration.
A Secret is intended for sensitive configuration such as credentials, tokens, and keys.
Secrets should still be handled carefully because simply putting a value in a Kubernetes Secret does not automatically make the entire secret-management process secure.
Work through the problem layer by layer:
Do not immediately assume that the Java HTTP client is the problem.
Test DNS resolution from the affected Pod.
kubectl exec -it <pod-name> -- nslookup <service-name>
Depending on the container image, tools such as dig or getent may also be useful.
Then investigate the Kubernetes DNS service, Service name, namespace, and DNS configuration.
Check:
A very common problem is a selector that does not match the labels on the Pods.
If the Service has no matching endpoints, traffic has nowhere to go.
The Service cannot successfully route traffic to healthy backend Pods.
Clients may see connection failures, timeouts, or other errors depending on the network path.
Check the Service and its EndpointSlices to determine whether Kubernetes has discovered the expected backend Pods.
Intermittent failures require correlation rather than checking one component in isolation.
Investigate:
Distributed tracing can be particularly valuable because it can reveal whether failures occur at a specific downstream call.
Start with the latency measurement and determine where the time is being spent.
Check:
A distributed trace can help break a 5-second response into individual operations and identify the slowest component.
Use distributed tracing with propagated trace context.
For example:
Client → API Gateway → Order Service Pod → Payment Service Pod → Database
A single trace can connect operations across different Pods and services.
Trace IDs and span IDs can also be correlated with structured application logs.
Requests influence how Kubernetes schedules workloads.
Limits define resource boundaries for containers.
Incorrect values can cause several problems:
Resource configuration should be based on measured application behavior rather than arbitrary numbers.
When a node experiences memory pressure, Kubernetes may evict Pods according to its eviction behavior and Pod priorities.
This can result in applications being restarted or rescheduled elsewhere.
Node-level memory pressure should therefore be investigated separately from JVM heap usage.
Check the Pod status and node conditions.
Investigate:
The important question is whether the problem originated from the application or from resource pressure on the node.
Compare affected Pods with Pods running on other nodes.
If multiple unrelated applications on the same node experience problems, the node itself becomes a strong suspect.
Check node conditions, resource usage, events, networking, storage, and recent infrastructure changes.
The Kubernetes Horizontal Pod Autoscaler, or HPA, adjusts the number of Pod replicas based on configured metrics.
A common setup uses CPU or memory utilization.
For example:
Traffic increases → CPU increases → HPA increases replicas → workload is distributed across more Pods.
For Spring Boot applications, autoscaling should ideally be evaluated using both infrastructure metrics and application-level behavior.
Possible reasons include:
For example, if the real bottleneck is a database, adding more Spring Boot Pods may increase database pressure instead of improving performance.
CPU-based scaling is simple and useful for CPU-bound applications.
However, CPU is not always a good representation of application load.
A Java API might experience high latency because of database connections or downstream services while CPU remains relatively low.
Custom metrics such as request rate, queue depth, or business-specific workload indicators can sometimes provide a better scaling signal.
Check:
kubectl rollout status deployment/<deployment-name>
kubectl describe deployment <deployment-name>
kubectl get pods
Also determine whether the new version is failing while the old version is still healthy.
A typical approach is to use multiple application replicas, readiness probes, graceful shutdown, and a rolling deployment strategy.
The new Pod should become ready before receiving production traffic, while existing healthy Pods continue serving requests.
Backward-compatible API and database changes are also important.
If the new deployment is unhealthy, use the deployment's rollout history and rollback mechanism.
kubectl rollout history deployment/<deployment-name>
kubectl rollout undo deployment/<deployment-name>
However, application rollback is only safe when database and API changes are also compatible with the previous version.
Compare the environments instead of assuming the code is different.
Check:
Containerized applications should not rely on local files, localhost assumptions, or developer-specific environment configuration.
First compare the new version with the previous version.
Look at:
Distributed tracing can reveal whether the latency originates inside the application or in a dependency.
If the problem clearly started after deployment, the code or configuration change should be investigated early.
I would use the three major observability signals together:
For a Spring Boot application, metrics can be exposed through Micrometer and collected by a monitoring system. Distributed tracing can help follow requests across microservices.
The important part is correlation. Trace IDs should make it possible to connect a request with the relevant application logs and trace spans.
This is where production engineering becomes more important than simply checking application logs.
I would investigate:
I would also compare normal traffic with peak traffic.
The objective is to determine which resource reaches saturation first.
Do not immediately increase CPU or memory.
Start by establishing the timeline.
Ask:
Then correlate Kubernetes and JVM telemetry.
Check CPU usage, CPU throttling, memory usage, GC activity, thread count, restarts, health probes, database connections, and downstream latency.
If CPU is high, identify the hot threads.
If memory is increasing, determine whether the heap or native memory is responsible.
If GC activity is increasing, investigate allocation rates and heap pressure.
If the application waits on a database or downstream service, investigate connection pools and timeouts.
This gives you a structured path from symptoms to root cause rather than guessing.
A Spring Boot microservice is deployed successfully, but after traffic increases:
How would you determine whether the root cause is the JVM, application code, Kubernetes resources, database, or downstream services?
Find out exactly when latency, CPU, memory, and restarts started increasing.
Compare the timeline with traffic changes, deployments, configuration changes, database changes, and downstream incidents.
Look at:
Investigate:
Use logs, profiling, and Java Flight Recorder where appropriate.
Look for expensive operations, unexpected loops, excessive object creation, blocked threads, synchronization problems, or recent code changes.
Investigate:
Use distributed tracing to determine whether requests are spending most of their time waiting for another microservice.
The root cause may become visible as a chain:
Traffic increases → CPU saturation → request latency increases → threads remain busy longer → memory increases → Pods restart → available capacity decreases → latency increases further.
Or the chain could be completely different:
Downstream service slows → HTTP connections remain occupied → thread pool fills → API latency increases → memory pressure increases.
That is why senior-level troubleshooting is about correlation, measurement, and elimination.
| Symptom | First Things to Investigate |
|---|---|
| CrashLoopBackOff | Logs, previous logs, exit code, probes, events |
| OOMKilled | Memory limit, heap, GC, native memory |
| High CPU | Hot threads, GC, CPU throttling, traffic |
| Pod Pending | Requests, node capacity, affinity, taints |
| Pod Evicted | Node pressure, memory, ephemeral storage |
| High API latency | Traces, database, threads, CPU, downstream calls |
| Service unavailable | Service, selectors, endpoints, readiness |
| DNS failure | Service name, namespace, cluster DNS |
| Restart loop | Application crash, liveness probe, memory |
| HPA not scaling | Metrics, resource requests, thresholds, scheduling |
| Deployment failure | ReplicaSet, Pods, probes, image, events |
Senior Java developers working with Kubernetes should be comfortable with a basic set of commands.
# Check Pods
kubectl get pods
# Get detailed Pod information
kubectl describe pod <pod-name>
# View application logs
kubectl logs <pod-name>
# View logs from the previous container
kubectl logs <pod-name> --previous
# Check deployments
kubectl get deployments
# Check deployment rollout
kubectl rollout status deployment/<deployment-name>
# Check Services
kubectl get services
# Check EndpointSlices
kubectl get endpointslices
# Check Nodes
kubectl get nodes
# Check resource usage
kubectl top pods
kubectl top nodes
# Execute a command inside a container
kubectl exec -it <pod-name> -- /bin/sh
When an interviewer asks:
"Your Spring Boot application is slow in Kubernetes. How would you troubleshoot it?"
They are usually not looking for a single command.
They want to see whether you can build a logical investigation.
A strong answer sounds like this:
Symptoms → Metrics → JVM → Application → Kubernetes → Database → Network → Downstream Services → Root Cause → Fix → Prevention
For example, don't simply say:
"I will increase the Pod memory."
Instead say:
"First I would determine whether the memory increase is caused by JVM heap usage, excessive allocation, a memory leak, or non-heap/native memory. I would correlate JVM metrics with container memory and GC activity before changing the resource limits."
That difference demonstrates production-level thinking.
Kubernetes troubleshooting becomes much easier when you stop looking at Kubernetes, Java, Spring Boot, databases, and networking as completely separate systems.
They are connected.
A database slowdown can increase Spring Boot latency.
Higher latency can increase thread usage.
More threads can increase memory consumption.
Memory pressure can restart Pods.
Fewer healthy Pods can increase traffic on the remaining Pods.
And suddenly a small dependency problem becomes a production incident.
That's why senior Java developers need to understand both application-level troubleshooting and Kubernetes-level troubleshooting.
The most important mindset is simple:
Don't guess. Measure, correlate, isolate, fix, and verify.
If you are preparing for a senior Java, Spring Boot, Microservices, Kubernetes, AWS, or Cloud Native interview, keep these scenarios as a practical troubleshooting checklist.
Real production problems rarely come with a clear error message. Your job is to find the signal inside the noise.
Common issues include CrashLoopBackOff, OOMKilled containers, CPU throttling, incorrect health probes, missing configuration, service connectivity failures, DNS problems, resource exhaustion, deployment failures, and JVM performance problems.
Start with the symptoms and collect evidence from Pod status, events, application logs, JVM metrics, CPU and memory usage, health probes, networking, database metrics, and distributed traces.
A Java OutOfMemoryError is raised by the JVM when it cannot satisfy a memory allocation. OOMKilled refers to the container being terminated by the operating system or Kubernetes environment because of memory pressure or exceeding its memory boundary. They can be related but are not the same event.
Possible causes include CPU throttling, JVM garbage collection, memory pressure, thread pool exhaustion, database connection pool exhaustion, slow database queries, network problems, or slow downstream services.
Check the current and previous container logs, Pod events, exit code, health probes, environment variables, application configuration, and memory limits. The goal is to identify why the container process is repeatedly exiting.
Distributed tracing follows requests across multiple Pods and microservices. It helps identify whether latency or errors originate in the Java application, database, network, or downstream service.
0 Comments