πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Deployments beginner ⏱ 8 minutes K8s 1.28+

K8s Init Containers: Setup Before Main

Use Kubernetes init containers to run setup tasks before main containers start. Database migrations, config fetching, dependency checks, and ordering.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: Init containers run to completion before main containers start. Define in spec.initContainers[] β€” they execute sequentially. Use cases: wait for a database to be ready (nslookup db-service), run database migrations, download config files, or set filesystem permissions. If any init container fails, the pod restarts.

The Problem

Applications often need setup before they can start:

  • Database must be reachable before the app connects
  • Config files must be downloaded from external sources
  • Filesystem permissions must be set
  • Schema migrations must run before the new version starts

The Solution

Basic Init Container

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  initContainers:
  # Init 1: Wait for database
  - name: wait-for-db
    image: busybox:1.36
    command: ['sh', '-c', 'until nslookup db-service.default.svc.cluster.local; do echo waiting for db; sleep 2; done']
  
  # Init 2: Run migrations (runs after init 1 completes)
  - name: run-migrations
    image: myapp:v2
    command: ['./migrate', '--target', 'latest']
    env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: db-creds
          key: url
  
  containers:
  - name: web
    image: myapp:v2
    ports:
    - containerPort: 8080

Common Patterns

# Download config from external source
initContainers:
- name: fetch-config
  image: curlimages/curl
  command: ['curl', '-o', '/config/app.yaml', 'https://config.example.com/app.yaml']
  volumeMounts:
  - name: config
    mountPath: /config

# Set file permissions
- name: fix-permissions
  image: busybox:1.36
  command: ['sh', '-c', 'chown -R 1000:1000 /data']
  volumeMounts:
  - name: data
    mountPath: /data

# Wait for another service
- name: wait-for-cache
  image: busybox:1.36
  command: ['sh', '-c', 'until nc -z redis-service 6379; do sleep 1; done']

# Clone git repo
- name: clone-repo
  image: alpine/git
  command: ['git', 'clone', 'https://github.com/example/configs.git', '/repo']
  volumeMounts:
  - name: repo
    mountPath: /repo

Init vs Sidecar vs Main

FeatureInit ContainerSidecar (K8s 1.28+)Main Container
Runs before mainβœ… Sequentialβœ… Starts beforeN/A
Runs continuously❌ Exits on completionβœ…βœ…
Shares volumesβœ…βœ…βœ…
Restarts pod on failureβœ…βŒ (restarts itself)Depends on policy
Resource requestsSeparate (max of inits)Added to pod totalAdded to pod total

Resource Handling

# Pod effective resources = max(sum(containers), max(initContainers))
initContainers:
- name: heavy-init
  resources:
    requests:
      cpu: "2"         # Needs 2 CPU during init
      memory: 2Gi
containers:
- name: app
  resources:
    requests:
      cpu: 500m        # Only 500m during runtime
      memory: 256Mi

# Effective: 2 CPU during init, 500m during runtime
# Scheduler reserves max(2, 0.5) = 2 CPU for scheduling

Common Issues

Init container stuck β€” pod shows Init:0/2

Init container failing or waiting forever. Check logs: kubectl logs <pod> -c <init-container-name>.

Init containers re-run on pod restart

By design β€” init containers always re-run from scratch. Make them idempotent (safe to run multiple times).

DNS not resolving in init container

CoreDNS may not be ready yet. Add a retry loop with sleep instead of a one-shot nslookup.

Best Practices

  • Make init containers idempotent β€” they may run multiple times
  • Set timeouts on wait loops β€” don’t wait forever for dependencies
  • Use minimal images β€” busybox/curl for simple tasks, not the full app image
  • Share data via emptyDir volumes β€” init containers write, main containers read
  • Use native sidecar containers (K8s 1.28+) for continuous helper processes

Key Takeaways

  • Init containers run sequentially before main containers start
  • If any init container fails, the entire pod restarts
  • Common uses: dependency checks, migrations, config download, permission fixes
  • Resource requests are calculated as max(inits) vs sum(containers)
  • Init containers must be idempotent β€” pod restarts re-run all inits
#init-containers #pods #deployments #cka
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens