camzabriskie.com

Primers › Kubernetes

Why a pod keeps restarting

02 / 02 updated Oct 13, 2026
On this page
  1. A few terms
  2. Read the exit code first
  3. How a failed probe turns into a restart
  4. Why a healthy-looking app fails its probe
  5. An order to check things in
  6. References

A service in Kubernetes restarts every few hours. Its logs end in a normal-looking shutdown, there’s no crash in them, and the first guess is usually that it ran out of memory. That’s one possibility. There are others that look almost the same from the outside, and the fix for each is different, so it pays to know which one happened before raising any limits.

A few terms

Read the exit code first

kubectl describe pod shows the state of each container in the pod:

kubectl describe pod <pod>

For a container that has restarted, that part of the output looks something like this:

    State:          Running
      Started:      Tue, 06 Oct 2026 14:02:11 +0000
    Last State:     Terminated
      Reason:       Error
      Exit Code:    143
      Started:      Tue, 06 Oct 2026 10:15:40 +0000
      Finished:     Tue, 06 Oct 2026 14:02:09 +0000
    Restart Count:  4

Last State only goes back one run. Kubernetes keeps the last termination and nothing older, and it’s empty for a container that has never restarted [5]. A container that restarted four times shows why the fourth run ended, not the three before it. To see whether every restart ends the same way, read it again after each one. describe has no flag for older runs. The logs do: kubectl logs <pod> --previous prints the logs of the run before the current one, and only that one [6].

Last State narrows things down a lot:

Last State showsWhat happenedWhere to look
OOMKilled, exit code 137The container used more memory than its limit and the kernel killed it [4]Memory: raise the limit, or make the app use less
Error, exit code 143Something sent SIGTERM and the app shut down cleanly. When nobody deleted the pod, that’s usually the kubelet after a failed liveness probe [1], [7]Probe settings, CPU, and why the app stopped answering
Error, exit code 137, not OOMKilledThe app got SIGTERM, didn’t exit within the grace period (30 seconds by default), and was killed with SIGKILL [7]Same as 143, plus why the app ignores or is slow to handle SIGTERM
Error with another code, often 1The app exited on its own, with its own errorThe app’s logs from just before it ended

The second row surprises people most. Nothing ran out, no error is logged, and the log ends in what looks like a normal shutdown, because SIGTERM lets the app close down cleanly. A burst of “interrupted” errors in the last few seconds is that shutdown in progress, not its cause.

For Java services there’s one more case. The heap can fill up and throw OutOfMemoryError while the container itself is well under its limit, so it may not restart at all. Java heap size and container memory covers how to tell the two kinds of out-of-memory apart.

How a failed probe turns into a restart

A liveness probe is usually a request to a health endpoint in the app. Three settings decide how much silence the kubelet tolerates [1]:

With a 30-second period, a 10-second timeout, and a threshold of 3, an app that stops answering gets about 90 seconds before the kubelet gives up on it:

Three failed probes in a row, then a polite SIGTERM, then a forced SIGKILL only if the app doesn't stop within the grace period.

Why a healthy-looking app fails its probe

An app can go quiet for 90 seconds without anything being wrong in the usual sense:

The Kubernetes documentation also warns that liveness probes set up wrong can cause cascading failures: containers restarted under heavy load, more failed requests, and more load on the pods that are left [1]. The usual way into that trap is a liveness check that also tests a database or another service. When that dependency gets slow, every replica fails its probe at once and restarts together. Checks on dependencies belong in the readiness probe, whose failure only takes the pod out of rotation without restarting anything [1].

An order to check things in

  1. Read Last State with kubectl describe pod. OOMKilled means memory. 143, or 137 without OOMKilled, means a signal from outside, usually a probe.

  2. Read the events, which include the kubelet’s “Liveness probe failed” messages. Events are deleted after an hour by default, so read them soon after a restart [9]:

    kubectl get events --field-selector involvedObject.name=<pod>
  3. Compare the probe settings with how long the app takes to start and how long it can stall.

  4. Check for throttling in cpu.stat.

  5. For a Java service, read the live heap with jcmd, as in Java heap size and container memory. A heap far below its maximum isn’t the cause.

  6. Catch it in the act. The next time it starts stalling, take a thread dump and turn on garbage-collection logging, so the evidence exists when it happens again.

Once the cause is known, the fix usually follows from it: a startup probe for a slow start, a higher failure threshold or timeout for an app that stalls briefly, a higher CPU limit for one that’s throttled, or a memory change only when the evidence points at memory. A bigger memory limit does nothing for a probe failure.

References

Show all 9 sourcesHide sources
  1. [1] ↩ a b c d e f The Kubernetes Authors, “Liveness, Readiness, and Startup Probes,” Kubernetes Documentation. Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/
  2. [2] ↩ The Linux man-pages project, “signal(7),” Linux manual pages. Accessed: Oct. 13, 2026. [Online]. Available: https://man7.org/linux/man-pages/man7/signal.7.html
  3. [3] ↩ Free Software Foundation, “Exit Status,” Bash Reference Manual. Accessed: Oct. 13, 2026. [Online]. Available: https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
  4. [4] ↩ a b c The Kubernetes Authors, “Resource Management for Pods and Containers,” Kubernetes Documentation. Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
  5. [5] ↩ a b The Kubernetes Authors, “ContainerStatus v1 core,” Kubernetes API Reference (v1.34). Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#containerstatus-v1-core
  6. [6] ↩ The Kubernetes Authors, “kubectl logs,” Kubernetes Documentation. Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_logs/
  7. [7] ↩ a b The Kubernetes Authors, “Pod Lifecycle,” Kubernetes Documentation. Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
  8. [8] ↩ The Linux Kernel documentation, “Control Group v2,” The Linux Kernel Admin Guide. Accessed: Oct. 13, 2026. [Online]. Available: https://docs.kernel.org/admin-guide/cgroup-v2.html
  9. [9] ↩ The Kubernetes Authors, “kube-apiserver,” Kubernetes Documentation (command line tools reference). Accessed: Oct. 13, 2026. [Online]. Available: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/

Every source cited across the primers is collected on one page.