## Intro

Debugging a running pod in Kubernetes requires more than checking logs. When a pod is misbehaving but not crashing, you need to inspect its internal state without disrupting the workload. This article covers advanced techniques for debugging live pods, including ephemeral containers, process inspection, network analysis, and safe recovery workflows. It targets developers, DevOps engineers, and SREs who need to diagnose issues in production-like environments.

The core principle is operational safety: observe before changing, limit the blast radius, use placeholders for secrets, verify results, and document recovery steps. We will explore commands, expected outputs, and failure signals to help you move from symptom to solution.

## Prerequisites and Environment Inventory

Before debugging, confirm your cluster and tools are ready.

- Kubernetes version 1.23 or later for kubectl debug with ephemeral containers.

- kubectl client version within one minor version of the server.

- Cluster access with permission to create pods and exec into containers.

- Enable the EphemeralContainers feature gate if on older versions (GA in 1.25).

Verify your environment with:

kubectl version --short
# Example output:
# Client Version: v1.27.2
# Server Version: v1.27.3 
 Check that ephemeral containers are allowed by listing API resources:

kubectl api-resources | grep -i ephemeral
# Example output:
# ephemeralcontainers pods true EphemeralContainer 
 If the resource is missing, you may need to update your cluster or use older debugging methods like modifying the deployment spec.

## Understanding Pod States and Debugging Entry Points

A pod's STATUS field from kubectl get pods gives the first clue. Common statuses include Running , Pending , CrashLoopBackOff , Error , and Completed . Each state suggests different debugging approaches.

- Running : Pod is scheduled and at least one container is running. Internal issues may still exist.

- Pending : Pod cannot be scheduled, often due to resource constraints or node selectors.

- CrashLoopBackOff : A container starts and then exits with an error repeatedly. Logs from the previous instance are crucial.

- Error : A container terminated with an error.

- Completed : Container exited successfully; for debugging, you may need to keep it running.

To see detailed events and conditions:

kubectl describe pod <pod-name> -n <namespace> 
 Review the Events section for scheduling failures, image pull errors, or probe failures.

<style>
.eno-quiz-widget{margin:2rem 0;padding:1.5rem;border-radius:12px;background:var(--eno-surface-lowest,#f7f7f8);border:1px solid var(--eno-border-soft,#e2e2e6);font-family:var(--eno-font-body,Inter,sans-serif)}
.eno-quiz-widget .eno-quiz-kicker{font-family:var(--eno-font-label,"JetBrains Mono",monospace);font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;color:var(--eno-text-muted,#5f5f68);margin:0 0 .5rem}
.eno-quiz-widget .eno-quiz-question{font-family:var(--eno-font-heading,"Hanken Grotesk",sans-serif);font-size:1.0625rem;font-weight:600;margin:0 0 1rem;color:var(--eno-text-strong,#1a1a1f)}
.eno-quiz-widget .eno-quiz-options{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.eno-quiz-widget .eno-quiz-option{display:block;width:100%;min-height:44px;text-align:left;padding:.625rem .875rem;border-radius:8px;border:1.5px solid var(--eno-border-soft,#e2e2e6);background:#fff;font-size:.9375rem;cursor:pointer;transition:border-color var(--eno-motion-base,180ms ease-out),background var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-option:hover{border-color:var(--eno-primary,#0059bb)}
.eno-quiz-widget .eno-quiz-option:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-option[aria-pressed="true"]{border-color:var(--eno-primary,#0059bb);background:rgb(0 89 187 / 0.06)}
.eno-quiz-widget .eno-quiz-option[data-correct="true"].eno-quiz-revealed{border-color:var(--eno-success,#17803a);background:rgb(23 128 58 / 0.08)}
.eno-quiz-widget .eno-quiz-option[data-correct="false"].eno-quiz-revealed.eno-quiz-was-selected{border-color:var(--eno-error,#ba1a1a);background:var(--eno-error-soft,#ffdad6)}
.eno-quiz-widget .eno-quiz-option-icon{display:inline-block;width:1.1em;margin-right:.4em;font-weight:700}
.eno-quiz-widget .eno-quiz-submit{margin-top:1rem;min-height:44px;padding:.5rem 1.25rem;border-radius:8px;border:none;background:var(--eno-primary,#0059bb);color:#fff;font-weight:600;font-size:.9375rem;cursor:pointer;transition:opacity var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-submit:disabled{opacity:.5;cursor:not-allowed}
.eno-quiz-widget .eno-quiz-submit:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-explanation{margin-top:1rem;padding:.875rem 1rem;border-radius:8px;font-size:.9375rem;line-height:1.5;display:none}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-visible{display:block}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-correct{background:rgb(23 128 58 / 0.08);color:var(--eno-success,#17803a)}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-incorrect{background:var(--eno-error-soft,#ffdad6);color:var(--eno-error,#ba1a1a)}
@media (prefers-reduced-motion: reduce){.eno-quiz-widget *{transition:none!important}}
</style><div class="eno-quiz-widget" role="group" aria-label="Quick check question">
Quick check 1 of 2

What is the first step in debugging a Pod according to the reference passage?

- Checking the pod's logs
- Creating an ephemeral container
- Running kubectl describe pods ${POD_NAME}
- Deleting the pod and recreating it

<button type="button" class="eno-quiz-submit" disabled>Submit</button>
<div class="eno-quiz-explanation">The passage states: &#39;The first step in debugging a Pod is taking a look at it. Check the current state of the Pod and recent events with the following command: kubectl describe pods ${POD_NAME}&#39;.</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Advanced Debugging with Ephemeral Containers

Ephemeral containers are the modern way to debug a running pod without restarting it. They share the pod's network, process namespace, and optionally other namespaces, allowing you to inspect from inside.

### When to Use Ephemeral Containers

- The pod has no shell in its existing containers (distroless images).

- You need to attach debugging tools without modifying the original container.

- You want to observe process-level activity without stopping the container.

### Creating an Ephemeral Container with kubectl debug

The basic command:

kubectl debug -it <pod-name> --image=busybox --target=<container-name> -n <namespace> 
 Example:

kubectl debug -it my-app-pod --image=busybox --target=my-app -n production 
 You will be dropped into a shell inside the ephemeral container. Now you can inspect files, run network commands, or use debugging tools.

### Sharing Process Namespace

By default, the ephemeral container does not share the process namespace, so you won't see the target container's processes. To share it, you must create the ephemeral container using a JSON patch or a YAML file because kubectl debug does not have a flag for this.

Example patch file debug-pod.yaml :

apiVersion: v1
kind: Pod
metadata:
 name: my-app-pod
 namespace: production
spec:
 ephemeralContainers:
 - name: debugger
 image: busybox
 command:
 - sleep
 - "3600"
 targetContainerName: my-app
 securityContext:
 runAsUser: 0
 stdin: true
 tty: true 
 Apply with:

kubectl replace --raw /api/v1/namespaces/production/pods/my-app-pod/ephemeralcontainers -f debug-pod.yaml 
 Then attach:

kubectl attach -it -n production my-app-pod -c debugger 
 Inside, run ps aux to see the target container's processes.

### Copying Files

Ephemeral containers can be used to copy files to and from the pod using kubectl cp . This is useful for extracting core dumps or adding debugging tools.

From pod to local:

kubectl cp production/my-app-pod:/app/data -c debugger ./local-data 
 From local to pod:

kubectl cp ./my-tool production/my-app-pod:/tmp/my-tool -c debugger 

### Security Considerations

 Ephemeral containers run with the same privileges as the user specified in the security context. Avoid running as root unless necessary, and clean up after debugging. The ephemeral container remains until the pod is deleted; you can remove it by patching the pod.

## Inspecting Processes and Runtime State

When you cannot use ephemeral containers, you can still gather information with kubectl exec if the target container has a shell.

### Executing Commands in the Target Container

kubectl exec -it <pod-name> -n <namespace> -- /bin/sh 
 If the container runs as a non-root user, you may need --user or --privileged flags, but use them with caution.

### Checking Process List

kubectl exec <pod-name> -n <namespace> -- ps aux
# Example output:
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.1 0.3 123456 7890 ? Ssl 10:00 0:01 python app.py
# root 250 0.0 0.1 65432 1234 ? Ss 10:05 0:00 /bin/sh 
 This shows whether the expected process is running and its resource usage.

### Filesystem Inspection

kubectl exec <pod-name> -n <namespace> -- df -h
kubectl exec <pod-name> -n <namespace> -- du -sh /app 
 Check for disk space issues or unexpected files.

### Runtime Information via /proc

You can access /proc inside the container for runtime details:

kubectl exec <pod-name> -n <namespace> -- cat /proc/1/status 
 This gives memory, CPU, and other details about PID 1.

## Network Debugging Inside the Pod

Network issues are common. Use tools from inside the pod to test connectivity and DNS.

### Testing DNS Resolution

kubectl exec <pod-name> -n <namespace> -- nslookup kubernetes.default
# Expected output:
# Server: 10.96.0.10
# Address: 10.96.0.10:53
# Name: kubernetes.default.svc.cluster.local
# Address: 10.96.0.1 
 If DNS fails, check the resolv.conf and the cluster DNS service.

### Checking Connectivity with curl

kubectl exec <pod-name> -n <namespace> -- curl -v http://service-name.namespace.svc.cluster.local 
 If curl is not available, use wget or nc .

### Inspecting Socket and Routing

kubectl exec <pod-name> -n <namespace> -- netstat -tulpn
kubectl exec <pod-name> -n <namespace> -- ip route 
 These commands help identify listening ports and routing problems.

### Using a Debug Container for Network Tools

If the target container lacks network tools, create an ephemeral container with network tools image, like nicolaka/netshoot :

kubectl debug -it <pod-name> --image=nicolaka/netshoot --target=<container-name> -n <namespace> 
 Then run tcpdump , nmap , etc.

<style>
.eno-quiz-widget{margin:2rem 0;padding:1.5rem;border-radius:12px;background:var(--eno-surface-lowest,#f7f7f8);border:1px solid var(--eno-border-soft,#e2e2e6);font-family:var(--eno-font-body,Inter,sans-serif)}
.eno-quiz-widget .eno-quiz-kicker{font-family:var(--eno-font-label,"JetBrains Mono",monospace);font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;color:var(--eno-text-muted,#5f5f68);margin:0 0 .5rem}
.eno-quiz-widget .eno-quiz-question{font-family:var(--eno-font-heading,"Hanken Grotesk",sans-serif);font-size:1.0625rem;font-weight:600;margin:0 0 1rem;color:var(--eno-text-strong,#1a1a1f)}
.eno-quiz-widget .eno-quiz-options{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.eno-quiz-widget .eno-quiz-option{display:block;width:100%;min-height:44px;text-align:left;padding:.625rem .875rem;border-radius:8px;border:1.5px solid var(--eno-border-soft,#e2e2e6);background:#fff;font-size:.9375rem;cursor:pointer;transition:border-color var(--eno-motion-base,180ms ease-out),background var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-option:hover{border-color:var(--eno-primary,#0059bb)}
.eno-quiz-widget .eno-quiz-option:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-option[aria-pressed="true"]{border-color:var(--eno-primary,#0059bb);background:rgb(0 89 187 / 0.06)}
.eno-quiz-widget .eno-quiz-option[data-correct="true"].eno-quiz-revealed{border-color:var(--eno-success,#17803a);background:rgb(23 128 58 / 0.08)}
.eno-quiz-widget .eno-quiz-option[data-correct="false"].eno-quiz-revealed.eno-quiz-was-selected{border-color:var(--eno-error,#ba1a1a);background:var(--eno-error-soft,#ffdad6)}
.eno-quiz-widget .eno-quiz-option-icon{display:inline-block;width:1.1em;margin-right:.4em;font-weight:700}
.eno-quiz-widget .eno-quiz-submit{margin-top:1rem;min-height:44px;padding:.5rem 1.25rem;border-radius:8px;border:none;background:var(--eno-primary,#0059bb);color:#fff;font-weight:600;font-size:.9375rem;cursor:pointer;transition:opacity var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-submit:disabled{opacity:.5;cursor:not-allowed}
.eno-quiz-widget .eno-quiz-submit:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-explanation{margin-top:1rem;padding:.875rem 1rem;border-radius:8px;font-size:.9375rem;line-height:1.5;display:none}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-visible{display:block}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-correct{background:rgb(23 128 58 / 0.08);color:var(--eno-success,#17803a)}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-incorrect{background:var(--eno-error-soft,#ffdad6);color:var(--eno-error,#ba1a1a)}
@media (prefers-reduced-motion: reduce){.eno-quiz-widget *{transition:none!important}}
</style><div class="eno-quiz-widget" role="group" aria-label="Quick check question">
Quick check 2 of 2

When can you use kubectl debug to create a copy of a Pod?

- When the pod is running normally
- When you want to change the pod's name
- When you can't run kubectl exec because the container lacks a shell or crashes on startup
- When you need to delete the pod

<button type="button" class="eno-quiz-submit" disabled>Submit</button>
<div class="eno-quiz-explanation">The passage says: &#39;Sometimes Pod configuration options make it difficult to troubleshoot in certain situations. For example, you can&#39;t run kubectl exec to troubleshoot your container if your container image does not include a shell or if your application crashes on startup. In these situations you can use kubectl debug to create a copy of the Pod with configuration values changed to aid debugging.&#39;</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Debugging with Core Dumps and Memory Analysis

For crashes or memory issues, you may need to capture a core dump.

### Enabling Core Dumps

Set ulimit -c unlimited in the container and ensure /proc/sys/kernel/core_pattern is writable or redirect to a mounted volume.

Example pod spec:

apiVersion: v1
kind: Pod
metadata:
 name: core-dump-pod
spec:
 containers:
 - name: app
 image: myapp:latest
 volumeMounts:
 - name: core-dumps
 mountPath: /cores
 securityContext:
 capabilities:
 add: ["SYS_PTRACE"]
 volumes:
 - name: core-dumps
 emptyDir: {} 
 Then, inside the container, set ulimit -c unlimited && cd /cores && ./app .

After crash, retrieve the core file:

kubectl cp core-dump-pod:/cores/core ./core 
 Analyze with gdb:

gdb ./app ./core 

## Failure Modes and Recovery Strategies

### Common Failure Modes

- OOMKilled (Out of Memory)

- Symptom: Pod restarts with reason OOMKilled in kubectl describe pod .

- Verification: Check kubectl get pod -o yaml for lastState.terminated.reason: OOMKilled .

- Recovery: Increase memory limits or optimize the application.

- CrashLoopBackOff

- Symptom: Pod status shows CrashLoopBackOff .

- Verification: kubectl logs --previous shows error from last crash.

- Recovery: Fix the application error.

- ImagePullBackOff

- Symptom: Pod cannot pull image, status ImagePullBackOff .

- Verification: kubectl describe pod shows registry authentication or image not found.

- Recovery: Correct image name or add imagePullSecrets.

- Crash due to Misconfiguration

- Symptom: Application exits immediately.

- Debug: Use kubectl exec to run the command manually if possible.

### Recovery Workflows

 Always have a rollback plan. Use kubectl rollout undo for deployments:

kubectl rollout undo deployment/my-app -n production 
 Check rollout status:

kubectl rollout status deployment/my-app -n production 
 If a pod is stuck, you can force delete it:

kubectl delete pod <pod-name> -n <namespace> --grace-period=0 --force 
 But be cautious: this may cause data loss.

## Operations Checklist

Follow this checklist for systematic debugging:

- Identify the pod and namespace : kubectl get pods -n production

- Check pod status and events : kubectl describe pod my-app-pod -n production

- View logs : kubectl logs my-app-pod -c my-app -n production --tail=100

- If crash-looping, view previous logs : kubectl logs my-app-pod -c my-app -n production --previous

- Check resource usage : kubectl top pod my-app-pod -n production

- Attach ephemeral container if needed : kubectl debug -it my-app-pod --image=busybox --target=my-app -n production

- Test network : From inside, run curl http://service or nslookup .

- Inspect processes : ps aux , df -h , du -sh /app .

- Make one change at a time and observe.

- Document findings and recovery steps .

## Conclusion

Debugging a running pod in Kubernetes requires a systematic approach that balances observation and intervention. Advanced techniques like ephemeral containers provide powerful ways to inspect live workloads without disruption. By following the principles of safe debugging, you can isolate issues quickly and recover with minimal impact. Always verify your environment, understand the pod state, and use the right tools for diagnosis. With practice, you will handle even the most complex pod problems with confidence.

As a next step, choose one technique from this article, such as ephemeral containers or process inspection, and apply it to a non-critical pod in your cluster. Record the commands and outputs, and build your own debugging runbook.