Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Pod Lifecycle and Restart Policies

By Kokil Thapa | Last reviewed: September 2026

Debugging a stuck Kubernetes workload usually comes down to misunderstanding Pod Lifecycle and Restart Policies. When a container exits unexpectedly or gets stuck in a pending state, the kubelet’s response is dictated entirely by these two interacting mechanisms. If you have ever stared at a CrashLoopBackOff status without knowing why the cluster keeps restarting your app, this guide explains the exact mechanics at play. For a broader look at cluster debugging, my article on debugging CrashLoopBackOff in Kubernetes covers specific troubleshooting workflows that complement this foundational knowledge.

What Are the Core Stages of Pod Lifecycle and Restart Policies?

A pod is not a single atomic unit; it is a sequence of distinct phases managed by the kubelet. Understanding Pod Lifecycle and Restart Policies requires separating the pod-level phase from individual container states. The pod phase is a high-level summary visible via kubectl get pods, but the actual restart decisions happen at the container level based on exit codes.

PendingRunningSucceededFailedTerminatingPod Phase TransitionsSchedulingInit + MainPreStop + SIGTERM
Pod Lifecycle and Restart Policies phase transitions from scheduling through terminal states

The five primary pod phases are:

  • Pending: The pod has been accepted by the API server, but one or more containers are not yet running. This includes time spent scheduling onto a node and pulling images. In my experience with Nepal-based infrastructure where bandwidth can be variable, large image pulls often extend this phase significantly.
  • Running: The pod is bound to a node, all containers have been created, and at least one container is still executing. Note that "Running" does not mean "healthy"—it simply means the process has started. Readiness probes determine traffic eligibility separately.
  • Succeeded: All containers terminated with exit code 0 and will not be restarted. This is typical for Jobs and CronJobs.
  • Failed: All containers have terminated, and at least one exited with a non-zero code or was terminated by the system. The restart policy determines if this state triggers a new attempt.
  • Unknown: The API server cannot communicate with the kubelet on the node hosting the pod. This usually indicates network partitioning or node failure rather than an application issue.

Critically, container states within a pod include Waiting, Running, and Terminated. A pod can report Running even if its main container is in Waiting state due to a missing ConfigMap or Secret. Always inspect individual container statuses with kubectl describe pod rather than relying solely on the phase column.

How Do RestartPolicy Options Control Container Recovery?

The restartPolicy field in the pod spec applies to all containers in the pod and is evaluated only when a container terminates. It does not affect liveness probe failures directly—those always trigger a restart regardless of policy—but governs what happens after a clean or unclean exit.

RestartPolicyBehaviorBest ForController Compatibility
AlwaysRestarts container on any exit code (0 or non-zero)Long-running web servers, APIs, daemonsDeployments, ReplicaSets, DaemonSets (default)
OnFailureRestarts only on non-zero exit codeData processing jobs, migrations, scriptsJobs, CronJobs
NeverNever restarts; pod enters Failed/Succeeded permanentlyOne-shot tasks, audit logs, forensic capturesJobs (manual inspection required)

A common mistake I see in production Laravel applications deployed to Kubernetes is using restartPolicy: Always for queue worker pods that should gracefully drain and exit. When the queue empties and the worker exits cleanly (code 0), Always forces an immediate restart, wasting resources. For workers designed to process a batch and stop, OnFailure ensures they only restart if something actually broke.

The restart backoff algorithm prevents runaway loops. After each restart, the kubelet waits 10 seconds, then doubles the delay up to a maximum of 5 minutes. This exponential backoff resets only after 10 minutes of successful execution. If your container crashes every 8 minutes, the backoff never resets, and you enter CrashLoopBackOff permanently. Understanding this timing is essential for diagnosing intermittent failures in Pod Lifecycle and Restart Policies.

How Do Probes Interact With Pod Lifecycle and Restart Policies?

Probes do not replace restart policies—they layer additional health semantics on top of them. Misconfiguring probes is the most frequent cause of unnecessary restarts in otherwise healthy applications. There are four probe types in Kubernetes 1.32+ (stable in 2026):

  1. startupProbe: Disables other probes until it succeeds. Essential for legacy PHP/Laravel apps with slow boot times. Without this, liveness checks kill the pod before initialization completes.
  2. livenessProbe: Determines if the container should be restarted. Failure triggers a kill and subject to restartPolicy. Use sparingly; a false positive causes cascading restarts.
  3. readinessProbe: Controls endpoint inclusion in Services. Failure removes the pod from load balancer rotation but does not restart it.
  4. sleepProbe: Newer addition for graceful shutdown coordination; less commonly used in standard web workloads.
Startup ProbeLiveness ProbeReadiness ProbeContainer RestartRemove from ServiceFAIL → KillFAIL → No TrafficProbe Decision MatrixBlocks others until OK
How startup, liveness, and readiness probes drive Pod Lifecycle and Restart Policies outcomes

For a Laravel application with heavy service provider bootstrapping, a practical configuration uses a generous startup probe to absorb cold starts, a conservative liveness probe checking /up (Laravel 11+ built-in health endpoint), and a readiness probe verifying database connectivity. Setting liveness initialDelaySeconds too low without a startup probe guarantees restart storms during deployment.

<!-- Example: Safe probe config for Laravel 12 -->
startupProbe:
  httpGet:
    path: /up
    port: 8080
  failureThreshold: 30
  periodSeconds: 2
livenessProbe:
  httpGet:
    path: /up
    port: 8080
  periodSeconds: 10
  timeoutSeconds: 3
readinessProbe:
  httpGet:
    path: /api/health
    port: 8080
  periodSeconds: 5

Note that probe failures bypass restartPolicy: Never for liveness checks. Even with Never, a failed liveness probe kills the container. Only exit-code-driven restarts respect the policy strictly. This distinction trips up many engineers configuring batch jobs that must not auto-restart but still need health monitoring during execution.

Why Does CrashLoopBackOff Happen Under Specific Restart Policies?

CrashLoopBackOff is not a pod phase—it is a container status reason indicating the kubelet is applying exponential backoff after repeated failures under restartPolicy: Always or OnFailure. It signals that the system is functioning as designed, but the application cannot sustain execution.

Common root causes tied to lifecycle misunderstandings include:

  • Missing environment variables or secrets: Container starts, reads config, exits immediately with code 1. Backoff escalates quickly because runtime is near-zero.
  • Liveness probe misconfiguration: App takes 45 seconds to boot, but liveness checks start at 10 seconds. Container is killed before ready, restarts, killed again, entering backoff loop.
  • Resource exhaustion: OOMKilled exits appear as code 137. If memory limits are too tight for peak usage, every restart hits the same ceiling.
  • Application logic errors: Unhandled exceptions in CLI commands or queue workers cause immediate exits. Unlike HTTP servers that catch errors per-request, batch processes die entirely.
Run0sDieExit 1Wait10sRunDieWait20sRunDieWait40sExponential Backoff TimelineEach failure doubles wait time up to 5m capCrashLoopBackOff = Active Backoff State
Exponential backoff intervals in Pod Lifecycle and Restart Policies during repeated failures

To diagnose, always check kubectl get events --sort-by=.lastTimestamp alongside pod description. Events reveal whether the kill came from a probe failure, OOM condition, or natural exit. For deeper troubleshooting patterns including log inspection and event correlation, refer to debugging CrashLoopBackOff in Kubernetes. On real client projects running Laravel queue workers, I have found that adding structured logging at the very first line of the command handler catches configuration errors before framework bootstrap fails silently.

How Should You Configure Pod Lifecycle and Restart Policies for Production Workloads?

Production configuration requires matching restart semantics to workload type. There is no universal setting. Deployments serving HTTP traffic should almost always use restartPolicy: Always with properly tuned probes. Batch Jobs benefit from OnFailure with explicit backoffLimit to prevent infinite retries. One-off administrative tasks should use Never to preserve failure evidence for manual review.

Key production practices:

  • Set resource requests and limits: Without limits, a single leaking container can destabilize the node, causing unrelated pods to be evicted and restarted unpredictably.
  • Use preStop hooks for graceful shutdown: HTTP servers need time to drain connections. A 5-second preStop sleep plus terminationGracePeriodSeconds: 30 prevents dropped requests during rolling updates.
  • Avoid latest tags: Image pull behavior changes between IfNotPresent and Always. Pin versions to ensure restarts use identical artifacts, eliminating "works after restart" mysteries caused by silent image updates.
  • Monitor restart counts: Alert on kube_pod_container_status_restarts_total exceeding thresholds. Frequent restarts indicate underlying issues even if the pod eventually stabilizes.

For teams managing multiple environments, consider reading about Kubernetes resource limits and requests to pair resource governance with restart policies effectively. Proper resource sizing reduces OOM-induced restarts by 60–80% in my experience with PHP workloads, which tend to have higher baseline memory footprints than Go or Rust services.

Practical Takeaways for Managing Pod Lifecycle and Restart Policies

Mastering Pod Lifecycle and Restart Policies separates operators who fight fires from those who design resilient systems. Start by auditing every pod spec in your cluster: verify restart policies match workload intent, confirm probes have appropriate thresholds, and ensure resource limits reflect actual usage patterns. Test failure modes deliberately in staging—kill containers, exhaust memory, simulate slow startups—to validate recovery behavior before production incidents force the lesson. If you need hands-on assistance tuning Kubernetes workloads for Laravel, Symfony, or custom PHP applications, reach out to discuss your infrastructure. Stable pods are built through intentional configuration, not hopeful defaults.

Frequently Asked Questions

Pending, Running, Succeeded, and Failed. Pending covers scheduling and image pulls. Running means at least one container is executing. Succeeded and Failed are terminal states for non-restartable pods, indicating completion or unrecoverable error respectively.

Always restarts on any exit. OnFailure restarts only if containers exit non-zero. Never prevents automatic restarts entirely. Default is Always for Deployments but must be Never or OnFailure for Jobs to prevent infinite crash loops during batch processing tasks.

Use Never for idempotent batch jobs where retries cause duplicate data or side effects. Use OnFailure when transient errors like API timeouts are expected and safe to retry automatically without manual intervention or external orchestration logic handling the failure state.

CrashLoopBackOff indicates repeated container failures with exponential backoff delays up to five minutes. Common causes include missing environment variables, failed health checks, insufficient memory causing OOMKills, or application bugs preventing startup. Check kubectl describe pod events and container logs to identify the specific exit code and root cause before adjusting restart policies or resource limits.

Liveness probes determine if a container needs restarting; failure triggers kubelet to kill and restart the container based on restartPolicy. Readiness probes control traffic routing; failure removes the pod from service endpoints without restarting it. Misconfiguring liveness as readiness causes unnecessary restarts during slow startups, while missing readiness probes route traffic to unready containers causing user-facing errors in production environments.

PreStop hooks execute before SIGTERM is sent, allowing graceful shutdown tasks like draining connections, flushing buffers, or completing in-flight requests. Without preStop hooks, load balancers may still route traffic to terminating pods during the default thirty-second grace period, causing dropped requests. In my experience deploying Laravel applications on Kubernetes, adding a preStop sleep or connection drain script significantly reduces 502 errors during rolling deployments and scaling events.

No, restartPolicy is immutable after pod creation. You must delete and recreate the pod or update the parent controller specification like Deployment or Job YAML. Attempting to patch restartPolicy directly returns a validation error. For production systems, always test restart behavior in staging first, as changing from Always to OnFailure can silently stop auto-recovery for critical services during off-hours incidents.

On restart within the same node, ephemeral emptyDir volumes persist across container restarts but are lost if the pod is deleted or rescheduled. PersistentVolumeClaims survive both restarts and rescheduling, reattaching to the new pod instance. StatefulSets guarantee stable volume identity across reschedules. Understanding this distinction prevents accidental data loss when debugging restart loops or performing maintenance on nodes running stateful workloads like databases or message queues.

OOMKilled exits with code 137 and triggers immediate restart under Always policy, potentially creating rapid crash loops that consume cluster resources. The kubelet applies backoff delays, but memory-hungry applications can still destabilize nodes. Set appropriate memory requests and limits based on actual usage patterns rather than guesses. Monitor with kubectl top pods and adjust limits incrementally. Consider Vertical Pod Autoscaler recommendations for right-sizing before increasing limits blindly.

Jobs require restartPolicy Never or OnFailure because Always would create infinite restarts after successful completion, defeating the purpose of finite batch workloads. Kubernetes enforces this validation at admission time. For long-running daemon-like processes, use DaemonSets or Deployments instead. If you need retry logic for Jobs, configure backoffLimit and activeDeadlineSeconds rather than relying on restartPolicy alone to manage failure recovery and prevent runaway job execution consuming cluster quotas.

Init containers run sequentially before app containers start and must complete successfully. If an init container fails, the pod enters CrashLoopBackOff respecting restartPolicy, blocking all subsequent containers indefinitely. Init containers restart independently with their own backoff cycle. Common pitfalls include network-dependent init tasks failing due to DNS delays or permission issues. Add timeout logic and idempotency to init scripts, and use postStart hooks in app containers for non-blocking initialization when possible.

RestartPolicy Always on compromised or vulnerable containers creates persistent attack surfaces that automatically recover after security patches or manual kills. Attackers exploit this for cryptominers or reverse shells. Combine restart policies with PodSecurityStandards, read-only root filesystems, and network policies. Audit restart frequency via metrics; abnormal patterns indicate breaches or misconfigurations. In legal-tech portals handling sensitive documents, I enforce strict resource limits and monitoring alerts alongside restart policies to detect anomalous container behavior before data exposure occurs.

Pending indicates scheduling failures, not application errors. Run kubectl describe pod to check Events for Insufficient CPU/memory, node taints, affinity conflicts, or PVC binding issues. Verify node capacity with kubectl top nodes and check PersistentVolume availability. Cluster autoscaler may be provisioning new nodes. Resource quotas or LimitRanges could block scheduling. Unlike runtime crashes, Pending never triggers restartPolicy; it requires infrastructure or configuration fixes. Address scheduler constraints before investigating application-level restart behaviors.

Yes, restartPolicy applies uniformly to all containers in a pod. One failing sidecar restarts the entire pod under Always policy, disrupting the main application even if it is healthy. This coupling makes sidecars risky for unstable auxiliary processes. Use separate Deployments for independent failure domains when possible. For tightly coupled sidecars like logging agents, ensure they handle errors gracefully and implement circuit breakers. Kubernetes 1.28+ native sidecars improve isolation but restartPolicy semantics remain pod-scoped for backward compatibility.

Track kube_pod_container_status_restarts_total per namespace and pod name. Alert on rates exceeding baseline thresholds rather than absolute counts, as some restarts are normal during deployments. Correlate with container_exit_code metrics to distinguish OOMKills from application errors. High restart frequency with zero exit codes suggests liveness probe misconfiguration. Export these via Prometheus and visualize in Grafana dashboards grouped by deployment. In production environments I maintain, restart rate alerts catch degradation before users report outages, enabling proactive investigation of underlying stability issues.

Share this article

What I've Built

Products I Build & Run

Legal-tech and language-services platforms I designed, built and operate — each running in production for real clients across Nepal and Australia.

More in the making — I keep shipping tools for Nepal's legal, language and digital work. Got an idea worth building?

Quick Contact Options
Choose how you want to connect me: