One of the most frustrating moments as a Kubernetes developer is when you go to launch your pod, but it fails to start because of a problem during initialization. Init containers are incredibly useful for setting up a pod before handing it off to the main container, but they introduce an additional point of failure. In this post, we'll take an in-depth look at init containers in Kubernetes: what they are, how they work, how they can fail, and what that means for your Kubernetes deployments.
What is an init container and why is it important?
An init container is a container that runs before the main container in a Pod. They're often used to prepare the environment so the main container has everything it needs to run. For example, imagine you want to deploy a large language model (LLM) in a Pod. LLMs require datasets that can be several GB large. You can create an init container that downloads these datasets to the node so that when the LLM container starts, it immediately has access to the data it needs.
How do init containers work?
To understand how init containers work, it helps to understand how Pods work in general. A Pod is a collection of one or more containers that share the same process, file, and network namespace. They use the same operating system kernel as the host, but are otherwise their own independent environment.
A Pod must have at least one container process running inside of it, but containers can come and go during its lifetime. A common example is sidecar containers, which spin up to perform some specific function like logging, then spin down when they're no longer needed. Gremlin, for example, uses sidecar containers to orchestrate Chaos Engineering experiments in Kubernetes.
Init containers, like the name implies, run during the Pod's initialization process. But unlike sidecars, init containers must finish running before the main container starts. To add to this, if you have multiple init containers defined, they'll all run sequentially until they've either completed successfully or failed. If an init container fails and the Pod's restartPolicy
is not set to Never
, the Pod will repeatedly restart until it succeeds. Otherwise, Kubernetes marks the entire Pod as failed with the status Init:CrashLoopBackOff.
How do I troubleshoot a failed init container?
Init containers fail for the same reasons regular containers do. The suggestions we present in our blog post on CrashLoopBackOffs also apply here:
- Examine the log output from the init container. For example, you can use the kubectl command line tool to pull logs from the container using
kubectl logs --previous <pod name> -c <init container name>
. - View the state of the overall pod using
kubectl describe pod <pod name>
. Details about the init container will be listed under theInit Containers
heading.
If the problem is due to limited resources, remember that init containers' resource usage varies based on how and where you define quotas and limits. For instance, an init container can use resources only for initialization. If you use multiple init containers and have defined resource requests, Kubernetes will reserve the highest of these.
How do I ensure my fix works?
When you've identified a cause and added a possible fix to your container image and/or manifest, redeploy it and monitor it to ensure it starts successfully. You can use the kubectl command-line tool, the Kubernetes Dashboard, or any other tool that reports on Pod status. If your pod starts up completely and has a PodInitializing
or Running
state, you've successfully fixed the problem.
What other Kubernetes risks should I be looking for?
Even if you've got your init pods running successfully, there's still the chance that the main container fails. If it fails enough times, it can enter a CrashLoopBackOff
state and refuse to start without intervention. Similarly, if your main container fails with an ImagePullBackOff
, this means that the container can't start due to a missing or invalid container image. Make sure you spelled the container name correctly and are using the correct container registry (Kubernetes defaults to Docker Hub).
We also recommend using resource requests and limits to control how much CPU, RAM, and storage is allocated to each container. While not strictly necessary, this can help prevent memory leaks, improve the efficiency of your nodes, and prevent containers from being evicted.
If you want to learn all about more kinds of Kubernetes failure modes and how to prevent them, check out our blog series on Kubernetes risks.