Kubernetes Init Containers


What is an Init Container?
As Kubernetes pods can have more than one container.
Init containers are specialized containers that run before app containers in a Kubernetes Pod. Unlike regular containers, init containers must complete successfully before the main application containers can start. This sequential execution pattern makes them perfect for setup tasks.
Why Use Init Containers?
Separating initialization logic from application code
Delaying application startup until dependencies are ready
Running setup operations with different security contexts
Pre-populating volumes with configuration or data
How Init Containers Work?
Before jumping into the example, let’s see how it works step by step.
When a Pod is created, the kubelet initializes all volumes and networks
Kubelet starts init containers sequentially in the order defined in Pod spec
Each init container must terminate completely before the next one starts
The kubelet waits for each init container to have exit code 0 before proceeding
If an init container fails, kubelet restarts it according to the Pod's
restartPolicy
Once all init containers complete successfully, kubelet initializes and starts all app containers simultaneously
Status of init containers is exposed in the Pod's
.status.initContainerStatuses
fieldInit containers rerun completely during Pod restarts (unlike regular containers)
Kubelet retains init container logs until the Pod is deleted, even after container termination
Let’s see a example: Django with PostgreSQL
In this example, Let’s start with the scenario where PostgreSQL database is ready before starting your Django application.
apiVersion: v1
kind: Pod
metadata:
name: django
spec:
initContainers:
- name: wait-for-postgres
image: postgres:13
command: [
'sh',
'-c',
'until pg_isready -h postgres-service -p 5432; do echo waiting for postgres; sleep 2; done;'
]
containers:
- name: django
image: <Image-name>:<Tag>
env:
- name: DATABASE_URL
value: "postgres://user:password@postgres-service:5432/app_db"
ports:
- containerPort: 8000
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/
volumes:
- name: nginx-config
configMap:
name: nginx-config
In this example, the init container uses pg_isready
from the official PostgreSQL image to check if the database is accepting connections. The Django application and Nginx containers only start after this verification succeeds.
Let’s deploy this pod.
Save the YAML as web-app.yaml
and apply it:
kubectl apply -f web-app.yaml
Check the pod status:
kubectl get pods
You’ll see the init container running first. Once it’s done, your app starts.
Resources and Volumes for Init Containers
Init containers can define resources and access volumes just like regular containers, with some important considerations:
Resource Requests and Limits
The highest resource request/limit for each resource across all init containers is used
The Pod's effective request/limit is the higher of the sum of app containers and the highest init container
This ensures init containers have enough resources without permanently reserving them
Volume Usage
Init containers can mount and modify volumes that app containers will later use
Volumes created by init containers are available to app containers
Changes made to shared volumes by init containers persist for app containers
Empty directories and persistent volumes can be shared across container
apiVersion: v1
kind: Pod
metadata:
name: django
spec:
initContainers:
- name: wait-for-postgres
image: postgres:13
command: ['sh', '-c', 'pg_isready -h postgres-service && echo "DB schema initialized" > /data/status.txt']
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
volumeMounts:
- name: shared-data
mountPath: /data
containers:
- name: django
image: <Image>:<Tag>
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
volumeMounts:
- name: shared-data
mountPath: /app/data
volumes:
- name: shared-data
emptyDir: {}
Init container vs Sidecar container
Init Container performs tasks that need to be completed before the main container can start, while Sidecar Container provides supplementary functionality to the main container.
Init Container runs to completion and must succeed before the main container starts, while Sidecar Container runs continuously alongside the main container.
Init Container is used for setup tasks like waiting for dependencies, fetching configs, or running migrations, while Sidecar Container is used for tasks like logging, monitoring, or proxying.
Init Container always runs first in the pod lifecycle, while Sidecar Container runs concurrently with the main container.
If an Init Container fails, the pod restarts it until it succeeds, while a failing Sidecar Container may or may not impact the main container depending on its role.
Init Container does not run simultaneously with the main container, while Sidecar Container shares resources and runs in parallel with the main container.
So, Init containers always run to completion and each init container must complete successfully before the next one begins. If any init container fails, Kubernetes restarts the Pod repeatedly until initialization succeeds and Init containers can access secrets, while preventing app containers from having these privileges. Thank you.
References:
https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
https://www.loft.sh/blog/kubernetes-init-containers
https://www.alibabacloud.com/blog/kubernetes-init-containers_594725
Subscribe to my newsletter
Read articles from Sushil Tiwari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
