What Are Init Containers and How Do They Work?

intermediate|podsdevopssreCKACKAD
TL;DR

Init containers are specialized containers that run to completion before any app containers start. They execute sequentially and are commonly used for setup tasks like populating shared volumes, waiting for dependencies, or running database migrations.

Detailed Answer

Init containers are specialized containers defined in a Pod spec that run before any of the application (app) containers start. They are a first-class Kubernetes feature designed to handle prerequisite tasks that must complete successfully before your main workload begins.

How Init Containers Work

When a Pod is scheduled onto a node, the kubelet executes init containers one at a time, in order. Each init container must terminate successfully (exit code 0) before the next one starts. Only after every init container has completed does the kubelet start the app containers defined in the containers array.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
    - name: wait-for-db
      image: busybox:1.37
      command:
        - "sh"
        - "-c"
        - |
          until nslookup postgres-service.default.svc.cluster.local; do
            echo "Waiting for database..."
            sleep 2
          done
    - name: run-migrations
      image: myapp/migrations:1.5
      command: ["./migrate", "--up"]
      envFrom:
        - secretRef:
            name: db-credentials
  containers:
    - name: app
      image: myapp/server:2.1
      ports:
        - containerPort: 8080
      resources:
        requests:
          cpu: "250m"
          memory: "256Mi"
        limits:
          cpu: "500m"
          memory: "512Mi"

In this example, the Pod first waits until the database DNS name resolves, then runs database migrations, and only then starts the application server.

Common Use Cases

Dependency Waiting

The most common use case is blocking Pod startup until an external dependency (a database, a message queue, another service) is available. This avoids embedding retry logic or startup delays inside your application code.

Configuration and Secret Fetching

Init containers can pull configuration from external sources like HashiCorp Vault, AWS Secrets Manager, or a Git repository and write them into a shared volume before the app container reads them.

initContainers:
  - name: fetch-config
    image: vault-agent:1.15
    command: ["vault", "agent", "-config=/etc/vault/config.hcl", "-exit-after-auth"]
    volumeMounts:
      - name: secrets-vol
        mountPath: /secrets
containers:
  - name: app
    image: myapp/server:2.1
    volumeMounts:
      - name: secrets-vol
        mountPath: /etc/app-secrets
        readOnly: true
volumes:
  - name: secrets-vol
    emptyDir:
      medium: Memory

File System Preparation

Init containers can clone Git repositories, download model weights, decompress archives, or set directory permissions before the main container starts.

Failure Behavior and Restart Policies

If an init container fails, Kubernetes behavior depends on the Pod's restartPolicy:

  • Always or OnFailure: The kubelet retries the failed init container with exponential backoff (up to 5 minutes). App containers never start until the init container succeeds.
  • Never: The Pod transitions to the Failed phase immediately.

You can check which init container failed using:

kubectl describe pod app-with-init
kubectl logs app-with-init -c wait-for-db

Resource Scheduling Considerations

Init containers run sequentially, not in parallel with app containers. Kubernetes calculates the effective resource request for a Pod as the maximum of:

  1. The highest single init container request
  2. The sum of all app container requests

This means a single init container requesting 1 Gi of memory will not add to the app container memory total for scheduling purposes unless it exceeds the sum of all app container memory requests.

Init Containers vs. Sidecar Containers

Starting with Kubernetes 1.28 (stable in 1.31), you can define native sidecar containers by adding restartPolicy: Always to an entry in the initContainers array. These containers start in init-container order but continue running alongside app containers for the Pod's lifetime. Traditional init containers, by contrast, run once and must exit before app containers begin.

Init Containers vs. PostStart Hooks

A postStart lifecycle hook runs immediately after a container starts, but it offers no ordering guarantees between multiple containers and provides no separate image context. Init containers give you full control over sequencing, distinct images, and explicit success/failure semantics.

Best Practices

  1. Keep init containers lightweight -- use minimal images like busybox or alpine to avoid slow image pulls.
  2. Set resource requests and limits on init containers, especially for memory-intensive tasks like migrations.
  3. Use shared emptyDir volumes to pass data from init containers to app containers.
  4. Avoid long-running init containers -- if a task needs to run continuously, use a sidecar instead.
  5. Add timeouts to waiting loops so Pods do not get stuck in Pending indefinitely.

Why Interviewers Ask This

Interviewers want to confirm that you understand Pod startup sequencing and can design initialization workflows. This reveals whether you can separate bootstrap logic from application logic cleanly.

Common Follow-Up Questions

What happens if an init container fails?
The kubelet retries the init container according to the Pod's restartPolicy. The app containers will never start until all init containers succeed.
Can init containers have resource limits different from app containers?
Yes. The effective init resource request is the max of all init container requests, since they run sequentially. This value is compared against the sum of app container requests, and the higher value is used for scheduling.
How do init containers differ from the sidecar container pattern in Kubernetes 1.28+?
Native sidecar containers use restartPolicy: Always in the initContainers block and run for the lifetime of the Pod. Traditional init containers run once to completion and then exit.

Key Takeaways

  • Init containers run sequentially and must all succeed before app containers start.
  • They share the same volumes as app containers but can use different images with different tooling.
  • Init containers are ideal for setup tasks that should not be embedded in the application image.

Related Questions