Init Containers & Lifecycle Hooks
Run setup tasks before your app starts and handle graceful shutdown with preStop hooks.
Init Containers
An init container runs to completion before any of the main containers start. This gives you sequenced, guaranteed setup:
Pod starts β init-container-1 runs β exits 0 β init-container-2 runs β exits 0 β main containers start (in parallel)
Key properties:
- Run sequentially β each must complete before the next starts
- If an init container fails, kubelet restarts it (respecting the Pod's restartPolicy)
- Main containers cannot start until all init containers succeed
- Can use a different image than the main container (e.g., a kubectl image for setup, vault for secret fetching)
Common Patterns
Pattern 1: Wait for a dependency
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z mysql-svc 3306; do sleep 2; done']
Pattern 2: Fetch secrets from Vault
initContainers:
- name: vault-init
image: vault:latest
command: ['vault', 'agent', 'render', '-config=/vault-agent.hcl']
# Writes secrets to a shared emptyDir volume
Pattern 3: Run database migrations
initContainers:
- name: migrate
image: myapp:latest
command: ['./manage.py', 'migrate', '--no-input']Lifecycle Hooks
Kubernetes provides two hooks that run code at specific moments in a container's lifecycle:
postStart
Fires immediately after a container is created β concurrently with the container's main process (ENTRYPOINT). The container does not reach Running state until postStart completes.
β οΈ Warning: postStart is NOT guaranteed to run before ENTRYPOINT. For strict ordering, use init containers instead.
preStop
Fires before SIGTERM is sent. Kubernetes waits for preStop to finish, then sends SIGTERM. Critical for graceful shutdown β drain in-flight requests, deregister from service discovery, flush write buffers.
lifecycle:
preStop:
exec:
command: ['/bin/sh', '-c', 'nginx -s quit; sleep 5']terminationGracePeriodSeconds
When a Pod is deleted:
kubectl delete pod nginx
β
preStop hook runs Pod removed from Service Endpoints
(simultaneously) (new traffic stops arriving)
β
SIGTERM sent to process
β (app drains in-flight requests)
[terminationGracePeriodSeconds countdown β default 30s]
β (if still alive after grace period)
SIGKILLFor apps that take longer than 30 seconds to drain, set terminationGracePeriodSeconds to match. Combine with a preStop sleep to give load balancers time to deregister the Pod:
spec:
terminationGracePeriodSeconds: 60
containers:
- lifecycle:
preStop:
exec:
command: ['sleep', '15'] # Wait for LB health check deregistration