PreStop hooks execute immediately before container termination, providing a mechanism to perform cleanup or graceful shutdown preparation before SIGTERM is sent. They’re part of Kubernetes’ managed lifecycle pattern, enabling applications to prepare for shutdown even when they can’t handle signals directly.

Execution Model

Blocking Call - The PreStop hook is a blocking, synchronous operation. Kubernetes waits for the hook to complete before proceeding with termination.

Executes Before SIGTERM - The hook runs before SIGTERM is sent to the container’s main process. This provides an opportunity for preparation that happens before the graceful shutdown signal.

Grace Period Inclusion - Hook execution time counts against the Pod’s terminationGracePeriodSeconds. If the hook takes 20 seconds and the grace period is 30 seconds, the main process only has 10 seconds to handle SIGTERM before SIGKILL.

Same Semantics as SIGTERM - The hook is for graceful shutdown preparation. It should complete quickly and exit cleanly, just like SIGTERM handling.

No Termination Prevention - Unsuccessful hook results (non-zero exit, HTTP errors, timeouts) don’t prevent Pod deletion. Kubernetes proceeds with SIGTERM and eventual SIGKILL regardless of hook outcome.

Use Cases

PreStop hooks solve specific shutdown scenarios:

Signal-Unaware Applications - Some applications can’t handle SIGTERM directly (legacy apps, third-party binaries). PreStop hooks provide graceful shutdown for these:

lifecycle:
  preStop:
    exec:
      command: ["/bin/graceful-shutdown.sh"]

The hook handles shutdown logic that the application can’t implement itself.

Service Deregistration - Remove the container from external load balancers or service registries before shutdown:

lifecycle:
  preStop:
    httpGet:
      path: /deregister
      port: 8080
      host: service-registry.default.svc.cluster.local

This pairs with PostStart hook registration.

Connection Draining - Allow time for in-flight connections to complete before starting shutdown:

lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 15"]

Even though Kubernetes removes Pods from Service endpoints before PreStop, some clients may have cached endpoints or persistent connections.

Cleanup Coordination - Perform cleanup tasks before main process shutdown:

lifecycle:
  preStop:
    exec:
      command:
      - /bin/sh
      - -c
      - |
        # Flush metrics to external system
        curl -X POST http://metrics-collector/flush
        # Close long-lived connections
        /close-connections.sh
        # Allow final operations to complete
        sleep 5

Hook Mechanisms

PreStop hooks use the same execution mechanisms as PostStart hooks:

Exec Handler

Runs a command inside the container:

apiVersion: v1
kind: Pod
metadata:
  name: prestop-exec
spec:
  terminationGracePeriodSeconds: 45
  containers:
  - name: app
    image: myapp:v1
    lifecycle:
      preStop:
        exec:
          command:
          - /bin/sh
          - -c
          - |
            echo "Starting graceful shutdown at $(date)"
            # Complete pending work
            /drain-work-queue.sh
            # Notify monitoring
            curl -X POST http://monitoring/shutdown-started
            echo "PreStop hook completed"

HTTP GET Handler

Makes an HTTP GET request to a container port:

apiVersion: v1
kind: Pod
metadata:
  name: prestop-http
spec:
  containers:
  - name: app
    image: myapp:v1
    lifecycle:
      preStop:
        httpGet:
          path: /api/shutdown
          port: 8080
          scheme: HTTP

The application implements the /api/shutdown endpoint to handle graceful shutdown preparation. The hook succeeds on 2xx responses.

Termination Sequence

Understanding where PreStop fits in the shutdown sequence is critical:

  1. Pod Deletion Initiated - User deletes Pod or Deployment scales down
  2. Endpoints Removed - Pod removed from Service endpoint lists
  3. PreStop Hook Executes - Blocking call, counts against grace period
  4. SIGTERM Sent - SIGTERM delivered to container main process
  5. Remaining Grace Period - Application has terminationGracePeriodSeconds - hookDuration to exit
  6. SIGKILL Sent - SIGKILL if process hasn’t exited

The PreStop hook happens early in this sequence, before SIGTERM.

Grace Period Coordination

PreStop hook duration affects grace period management:

Total Budget - terminationGracePeriodSeconds is the total time for hook + application shutdown:

spec:
  terminationGracePeriodSeconds: 60  # Total budget
  containers:
  - name: app
    lifecycle:
      preStop:
        exec:
          command: ["/hook.sh"]  # Takes 20 seconds

If the hook takes 20 seconds, the application has 40 seconds to respond to SIGTERM.

Hook Timeout - Keep hooks fast to preserve grace period for the main process:

#!/bin/sh
# Bad - uses entire grace period
sleep 55  # App gets only 5 seconds for SIGTERM
 
# Good - quick hook preserves shutdown time
curl -X POST http://service-registry/deregister --max-time 5
sleep 5  # Brief connection drain
# App gets 50 seconds for SIGTERM handling

Internal Timeouts - Implement timeouts within hooks to prevent them from consuming the entire grace period:

#!/bin/sh
timeout 10 /deregister.sh || echo "Deregistration timed out, continuing"
sleep 5
exit 0  # Always succeed quickly

PreStop vs SIGTERM Handling

PreStop hooks complement but don’t replace SIGTERM handling:

PreStop Hooks Are For:

  • Legacy applications that can’t handle signals
  • External system notification (service registries, monitoring)
  • Connection draining before shutdown begins
  • Preparation tasks that must happen before main process shutdown

SIGTERM Handling Is For:

  • Primary graceful shutdown logic
  • Completing in-flight work
  • Releasing resources (connections, locks, file handles)
  • Final cleanup and state persistence

Recommended Pattern: Use hooks for pre-shutdown tasks; SIGTERM handler performs actual shutdown.

Integration with Deployments

PreStop hooks affect deployment timing:

Rolling Deployment - PreStop hooks extend the time to shut down old Pods. Balance thorough shutdown with acceptable deployment speed.

Zero-Downtime Requirements - PreStop hooks can help achieve zero-downtime deployments by ensuring old Pods drain connections before new Pods take all traffic.

Common Pitfalls

Hook Holds Indefinitely - Hooks that hang consume the entire grace period:

preStop:
  exec:
    command: ["/wait-forever.sh"]  # Never exits

Always implement timeouts to ensure hooks complete:

#!/bin/sh
timeout 20 /cleanup.sh || echo "Cleanup timed out"
exit 0

Replacing SIGTERM Handling - PreStop hooks supplement SIGTERM handling, they don’t replace it. Always implement both: hook for preparation, SIGTERM handler for actual shutdown.

Consuming Grace Period - Slow hooks leave little time for SIGTERM handling:

terminationGracePeriodSeconds: 30
preStop:
  exec:
    command: ["/slow-task.sh"]  # Takes 25 seconds
# Only 5 seconds remain for SIGTERM handling!

Ensure hooks are fast or increase grace period appropriately.

Expecting Failure Prevention - Unsuccessful hooks don’t prevent termination:

preStop:
  exec:
    command: ["/must-succeed.sh"]  # Exit 1
# Pod still receives SIGTERM and continues termination

Kubernetes proceeds with shutdown regardless of hook outcome.

Observability

Debugging PreStop hook issues:

Check Pod Events:

kubectl describe pod mypod

Look for:

Normal   Killing   Stopping container app
Warning  Failed    PreStop hook failed: command '/hook.sh' exited with 1

Measure Hook Duration:

# Compare deletion timestamp to termination timestamp
kubectl get pod mypod -o yaml | grep -E "(deletionTimestamp|terminatedAt)"

Log Hook Execution:

preStop:
  exec:
    command:
    - /bin/sh
    - -c
    - |
      echo "PreStop started at $(date)" | tee -a /var/log/hooks.log
      /cleanup.sh 2>&1 | tee -a /var/log/hooks.log
      echo "PreStop completed at $(date)" | tee -a /var/log/hooks.log

Access logs through shared volumes or debug containers.

Best Practices

Keep Hooks Fast - PreStop hooks should complete in seconds, not minutes. Long hooks delay Pod termination and extend deployment times.

Implement Timeouts - Always use timeouts to prevent hooks from hanging:

timeout 15 /deregister-from-lb.sh || true
sleep 5
exit 0

Use for Preparation Only - PreStop hooks prepare for shutdown; SIGTERM handlers perform shutdown:

  • PreStop: Deregister from external services, drain connections
  • SIGTERM: Complete work, release resources, exit

Coordinate with Grace Period - Ensure total hook time + application shutdown time fits within grace period:

terminationGracePeriodSeconds: 60
# Hook: 15 seconds (deregister + drain)
# SIGTERM handling: 40 seconds (complete work, cleanup)
# Buffer: 5 seconds (safety margin)

Handle Hook Failures Gracefully - Design hooks to succeed even when operations fail:

#!/bin/sh
curl -X POST http://registry/deregister --max-time 5 || echo "Deregister failed, continuing"
sleep 5
exit 0  # Always succeed

Pair with PostStart - If using PostStart for registration, use PreStop for cleanup:

lifecycle:
  postStart:
    httpGet:
      path: /register
      port: 8080
  preStop:
    httpGet:
      path: /deregister
      port: 8080

Consider Commandlet Pattern - For sophisticated lifecycle logic, the Commandlet pattern provides more control than hooks alone.

PreStop hooks enable graceful shutdown preparation within managed lifecycle, particularly for applications that can’t handle SIGTERM directly or need external coordination before shutdown begins.