Skip to main content

Understanding Kubernetes Pod Lifecycle

A deep dive into the Kubernetes pod lifecycle - from pending to running to termination. Learn how to handle graceful shutdowns and lifecycle hooks.

Pods are the smallest deployable units in Kubernetes. Understanding their lifecycle is crucial for building reliable applications.

Pod Phases #

A pod goes through several phases during its lifetime:

Pending #

The pod has been accepted by the cluster but one or more containers haven’t been created yet. This includes time spent waiting for scheduling and downloading images.

status:
  phase: Pending
  conditions:
    - type: PodScheduled
      status: "True"

Running #

The pod has been bound to a node, and all containers have been created. At least one container is still running or starting.

Succeeded #

All containers in the pod have terminated successfully and won’t be restarted.

Failed #

All containers have terminated, and at least one container terminated in failure.

Container Lifecycle Hooks #

Kubernetes provides two hooks for container lifecycle management:

PostStart #

Executed immediately after a container is created. There’s no guarantee it runs before the container’s ENTRYPOINT.

lifecycle:
  postStart:
    exec:
      command: ["/bin/sh", "-c", "echo 'Container started' >> /var/log/startup.log"]

PreStop #

Called immediately before a container is terminated. It’s blocking - the container won’t be killed until the hook completes.

lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "nginx -s quit; while killall -0 nginx; do sleep 1; done"]

Graceful Shutdown Pattern #

Here’s a pattern I use for graceful shutdowns in Go applications:

func main() {
    srv := &http.Server{Addr: ":8080"}
    
    go func() {
        if err := srv.ListenAndServe(); err != http.ErrServerClosed {
            log.Fatalf("HTTP server error: %v", err)
        }
    }()
    
    // Wait for SIGTERM
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
    <-quit
    
    // Graceful shutdown with timeout
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    
    if err := srv.Shutdown(ctx); err != nil {
        log.Fatalf("Server shutdown error: %v", err)
    }
}

Configuring Termination Grace Period #

By default, Kubernetes waits 30 seconds before forcefully killing a pod. You can adjust this:

spec:
  terminationGracePeriodSeconds: 60
  containers:
    - name: app
      image: myapp:latest

Liveness vs Readiness Probes #

Understanding the difference is essential:

  • Liveness Probe: Is the container healthy? If not, kill it and restart.
  • Readiness Probe: Is the container ready to serve traffic? If not, remove from service endpoints.
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

Key Takeaways #

  1. Always implement graceful shutdown in your applications
  2. Use preStop hooks for cleanup that must complete before termination
  3. Set appropriate terminationGracePeriodSeconds based on your app’s needs
  4. Implement both liveness and readiness probes

Understanding pod lifecycle helps you build applications that handle deployments, scaling, and failures gracefully.