K8s by Example: Lifecycle Hooks

Lifecycle hooks run at container start (postStart) and before termination (preStop). Use for initialization, service registration, graceful shutdown, and cleanup.

pod-lifecycle.yaml

Hooks are defined in the lifecycle block of a container. Both postStart and preStop support exec commands or HTTP requests.

spec:
  containers:
    - name: app
      image: my-app:v1
      lifecycle:
        postStart:
          exec:
            command: ["/bin/sh", "-c", "echo Started >> /var/log/app.log"]
        preStop:
          exec:
            command: ["/bin/sh", "-c", "sleep 15"]
pod-poststart.yaml

postStart runs immediately after container creation, in parallel with the entrypoint. Container is not Ready until postStart completes. If it fails, container is killed.

lifecycle:
  postStart:
    exec:
      command:
        - /bin/sh
        - -c
        - |
          curl -X POST http://consul:8500/v1/agent/service/register \
            -d '{"name":"my-app","port":8080}'
pod-prestop.yaml

preStop delays SIGTERM, allowing in-flight requests to complete. Critical for zero-downtime deployments. The sleep gives time for Service endpoints to update before container stops accepting traffic.

spec:
  terminationGracePeriodSeconds: 60
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command: ["/bin/sh", "-c", "sleep 15"]
pod-termination.yaml

Pod termination sequence: 1) Pod marked terminating, 2) Removed from Service endpoints (parallel with preStop), 3) preStop runs, 4) SIGTERM sent, 5) Wait for graceful shutdown, 6) SIGKILL after terminationGracePeriodSeconds.

spec:
  terminationGracePeriodSeconds: 60
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command:
              - /bin/sh
              - -c
              - |
                sleep 5
                /app/shutdown.sh
pod-http-hooks.yaml

HTTP hooks call an endpoint instead of running a command. Response status doesn’t matter, only connection errors cause failure. Useful for distroless or minimal containers without shell.

lifecycle:
  postStart:
    httpGet:
      path: /hooks/started
      port: 8080
  preStop:
    httpGet:
      path: /hooks/shutdown
      port: 8080
pod-grace-period.yaml

The terminationGracePeriodSeconds includes preStop execution time. If preStop takes 15s and you need 75s for graceful shutdown, set grace period to at least 90s. Default is 30s.

spec:
  terminationGracePeriodSeconds: 90
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command: ["sleep", "15"]
terminal

Debug hooks with events. postStart failures appear in Pod events. preStop failures are harder to catch, so add logging in your hook script. Hooks don’t have stdout/stderr.

$ kubectl describe pod my-app | grep -A5 Events
Events:
  Type     Reason               Age   Message
  Normal   Scheduled            60s   Successfully assigned default/my-app
  Normal   Pulled               58s   Container image "my-app:v1" already present
  Warning  FailedPostStartHook  55s   Exec lifecycle hook failed
  Normal   Killing              55s   FailedPostStartHook

Index | GitHub | Use arrow keys to navigate |