The Problem: Pods Stuck in Init:CrashLoopBackOff
Youâve deployed your manifest, but the Pod just sits there. In Kubernetes, initContainers act as gatekeepers. The main application container will not attempt to start until every init container finishes successfully with exit code 0. If one fails and enters a restart loop, your Pod becomes paralyzed in the Init:CrashLoopBackOff state.
Itâs a common bottleneck. Because the main container hasn't been created yet, running standard log commands usually returns nothing but frustration. You are left debugging a process that technically hasn't even begun.
Step 1: Pinpoint the Failing Container
Pods often run multiple init containers in sequence. Your first move is to identify which specific link in the chain is broken. Use the describe command to inspect the Podâs internal state.
kubectl describe pod <pod-name>
Scroll down to the Init Containers: section. You are looking for a non-zero exit code or a specific error state:
Init Containers:
install-assets:
Container ID: containerd://...
Image: node:18-alpine
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 127
In this case, the install-assets container is failing. The exit code 127 often suggests a "command not found" error within the container's shell.
Step 2: Extracting the Right Logs
A standard kubectl logs <pod-name> typically defaults to the main application container. Since that container doesn't exist yet, the command fails. To see the actual error, you must target the init container explicitly using the -c flag.
kubectl logs <pod-name> -c <init-container-name>
If the container is crashing rapidly, the current logs might be empty. Use the --previous flag to see the logs from the last failed execution. This is often where the "smoking gun" resides.
kubectl logs <pod-name> -c <init-container-name> --previous
Common Causes and Fixes
1. Shell Script and Binary Mismatches
Many developers use lightweight images like alpine or busybox for init tasks. If your script uses #!/bin/bash but the image only contains /bin/sh, the container will crash immediately. Similarly, missing permissions on a script file (chmod +x) will trigger a failure.
Refined Approach: Use a robust script block in your YAML and always include set -e to catch errors early.
command:
- /bin/sh
- -c
- |
set -e
echo "Checking database connectivity..."
# Use /dev/tcp if nc is missing
timeout 5 sh -c 'cat < /dev/null > /dev/tcp/db-service/5432'
2. Missing ConfigMaps or Secrets
If your init container requires a database password from a Secret that doesn't exist in the current namespace, the Pod will fail. Kubernetes won't even start the container if the valueFrom reference is missing. However, if the secret exists but the key is wrong, your script might crash during execution.
The Fix: Verify your secrets with kubectl get secret and ensure the keys match your env definitions exactly.
3. Resource Exhaustion (OOMKilled)
Init containers that perform heavy liftingâlike running database migrations or compiling assetsâoften need more resources than the main app. If you set a memory limit of 128Mi but the migration tool peaks at 256Mi, the kernel will kill the process.
Solution: Look for Reason: OOMKilled in the describe pod output. Increase the limits specifically for the init container:
resources:
limits:
memory: "512Mi"
cpu: "500m"
4. RBAC and Permissions Errors
Does your init container use curl to talk to the Kubernetes API? If so, it needs a ServiceAccount with the right Roles. Without them, your logs will show 403 Forbidden errors. Always check that the Pod's serviceAccountName has the necessary permissions to perform its task.
Verification: Confirming the Fix
After updating your manifest and applying the changes, monitor the transition. A healthy Pod will progress through these stages:
Init:0/1(The first init container is starting).PodInitializing(All init containers finished; the main container is pulling).Running(Success).
Check the events log using kubectl get events --sort-by='.lastTimestamp' to ensure no underlying scheduling issues remain.
Key Takeaways
- Init containers are sequential: They run one by one. If one fails, the whole Pod stops.
- No health checks: Init containers do not support liveness or readiness probes. They rely entirely on exit codes.
- Idempotency is vital: Because init containers can restart multiple times, their scripts must be safe to run repeatedly without breaking your data.
- Always use
-c: You cannot debug what you cannot see. Targeted logging is your most powerful tool.

