In real-world applications, your app often depends on something being ready before it can start:
- A config file that needs to be generated
- A database that must be reachable
- A volume that has to be pre-populated
- A service that must complete a health check
Rather than bloating your main container with complex startup scripts, Kubernetes gives you Init containers—lightweight, throwaway containers that run in order and exit before your app launches.
This approach keeps your main container clean, modular, and focused only on running your application.
Key Characteristics
- Run sequentially: Init containers execute one at a time, in the order they’re defined.
- Block startup: The pod’s main containers won’t start until all Init containers have run successfully.
- Run only once: They run during the pod initialization phase and never again unless the pod restarts.
- Have their own specs: Each Init container can use a different image, environment, resources, and volume mounts from the main container.
Use Cases
Here are common patterns where Init containers are ideal:
Wait-for-service
Check if a database or API is reachable before the app starts:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z db-service 5432; do echo waiting; sleep 2; done']
Configuration injection
Pull configuration files from a secure location:
initContainers:
- name: config-downloader
image: curlimages/curl
command: ['sh', '-c', 'curl -o /config/settings.json https://config-service/settings.json']
volumeMounts:
- name: config-volume
mountPath: /config
Volume preparation
Extract files or pre-populate a shared volume:
initContainers:
- name: extract-assets
image: alpine
command: ['sh', '-c', 'cp -r /assets/* /data']
volumeMounts:
- name: shared-volume
mountPath: /data
Real-World Example: Full Pod Spec
apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
volumes:
- name: shared-data
emptyDir: {}
initContainers:
- name: init-script
image: busybox
command: ['sh', '-c', 'echo Hello from Init Container > /data/init.txt']
volumeMounts:
- name: shared-data
mountPath: /data
containers:
- name: main-app
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
In this example, the Init container writes a file to a shared volume. The main container then serves it using nginx.
Benefits of Init Containers
Separation of concerns: Keep init logic out of your app container
Improved reliability: Block startup until dependencies are ready
Reusability: Share Init containers across services
Better observability: Failures in Init containers are easier to debug separately
Monitoring and Troubleshooting
You can monitor Init containers using kubectl
:
kubectl get pod app-with-init -o jsonpath="{.status.initContainerStatuses[*].state}"
And get logs:
kubectl logs app-with-init -c init-script
If any Init container fails, the pod will stay in a Pending
or Init
state until it’s fixed.
Best Practices
- Keep them fast: Long-running Init containers delay pod startup.
- Fail fast and clearly: If something’s wrong (e.g., a DB is unreachable), exit with a clear error.
- Use them for non-idempotent tasks cautiously: Pods can restart and re-run Init containers.
- Share volumes wisely: Use
emptyDir
,configMap
, orsecret
volumes to exchange data between Init and main containers.
FAQs
Can Init containers run in parallel?
No. Init containers run sequentially, one after another. If one fails, the others don’t run.
Can they access the same volumes as app containers?
Yes! Volumes defined in the pod spec can be shared between Init and main containers.
Can I use sidecars instead?
Sidecars are always running alongside the main container. Init containers are run-once setup jobs. Use both for different purposes.