Skip to main content
RunBook Academy

KubernetesXI · Init Containers and SidecarsInit containers and sidecars

Init container ordering and readiness gates

Advanced⏱ ~16 minkubectl

What you'll learn

  • Configure multiple init containers with dependencies between them
  • Use readiness gates to control Pod readiness based on external conditions
  • Reason about the trade-offs between init containers and readiness gates
  • Diagnose init container ordering failures

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

When a workload needs multiple setup steps that depend on each other, init containers run sequentially. This lesson covers how the kubelet orders init containers, how to design multi-step setups, and how readiness gates complement init containers for external preconditions.

Init container ordering

Init containers run in the order they appear in spec.initContainers. The first container in the list runs first; the second runs only after the first succeeds; and so on.

spec:
  initContainers:
  - name: fetch-config      # 1st: runs first
    image: config-fetcher:1.0
    command: ["fetch", "--output=/config/app.conf"]
    volumeMounts:
    - name: config
      mountPath: /config
  - name: validate-config   # 2nd: runs after fetch-config
    image: validator:1.0
    command: ["validate", "/config/app.conf"]
    volumeMounts:
    - name: config
      mountPath: /config
  - name: migrate           # 3rd: runs after validate-config
    image: migrate/migrate:4
    command: ["migrate", "-path=/migrations", "up"]
  containers:
  - name: app
    image: app:1.0.0
    volumeMounts:
    - name: config
      mountPath: /etc/app

The sequence:

  1. fetch-config downloads configuration to /config.
  2. validate-config reads /config/app.conf and validates it.
  3. migrate runs the database migration.
  4. app starts with the configuration already validated.

Each init container’s output (in shared volumes) is input to the next.

sequenceDiagram
    participant I1 as fetch-config
    participant Vol as emptyDir: config
    participant I2 as validate-config
    participant I3 as migrate
    participant App as app

    I1->>Vol: writes app.conf
    I2->>Vol: reads app.conf
    I2->>I2: validates
    I3->>I3: runs migration
    App->>Vol: reads app.conf

Sharing state between init containers

Init containers share the Pod’s volumes. Files written by one init container are visible to subsequent init containers and the main containers (via the same volume mount).

spec:
  initContainers:
  - name: generate-tls
    image: cert-generator:1.0
    command: ["gen", "--output=/certs/server.crt", "--key=/certs/server.key"]
    volumeMounts:
    - name: certs
      mountPath: /certs
  - name: verify-tls
    image: cert-validator:1.0
    command: ["verify", "/certs/server.crt"]
    volumeMounts:
    - name: certs
      mountPath: /certs
  containers:
  - name: app
    image: app:1.0.0
    volumeMounts:
    - name: certs
      mountPath: /etc/app/certs
volumes:
- name: certs
  emptyDir: {}

The init containers share the certs volume. The main container mounts the same volume at a different path.

Volume requirements across init containers

Each init container can declare different volume mounts:

spec:
  initContainers:
  - name: db-migration
    image: migrate/migrate:4
    command: ["migrate", "-path=/migrations", "up"]
    volumeMounts:
    - name: migrations
      mountPath: /migrations
  - name: secret-loader
    image: vault:1.15
    command: ["vault", "read", "-format=json", "secret/data/app"]
    volumeMounts:
    - name: secrets
      mountPath: /secrets
  containers:
  - name: app
    image: app:1.0.0
    volumeMounts:
    - name: secrets
      mountPath: /etc/app/secrets
volumes:
- name: migrations
  configMap:
    name: db-migrations
- name: secrets
  emptyDir: {}

Each init container has its own mount requirements; the Pod’s volumes list aggregates them.

Init container restart on failure

If an init container fails (non-zero exit), the kubelet retries the Pod. The retry uses exponential backoff (10s, 20s, 40s, etc., capped at 5 minutes).

kubectl get pod web-7c8 -o jsonpath='{.status.initContainerStatuses[0].restartCount}'
# 5

The init container has been retried 5 times. The Pod is still Pending. After a successful retry, the Pod proceeds to the next init container.

For init containers that should fail fast (e.g., a configuration validation that always fails), the Pod will be stuck in Pending forever. The diagnosis is to check the init container’s logs.

Readiness gates

Init containers gate Pod start. Readiness gates gate Pod readiness — a separate, more flexible mechanism.

spec:
  readinessGates:
  - conditionType: example.com/feature-ready
  containers:
  - name: app
    image: app:1.0.0

A readiness gate is a custom condition type that must be True for the Pod to be Ready. The kubelet does not automatically set this condition; an external actor must set it via the Pod’s status subresource.

kubectl patch pod web-7c8 --subresource=status --type=merge -p '
{
  "status": {
    "conditions": [
      {
        "type": "example.com/feature-ready",
        "status": "True"
      }
    ]
  }
}'

Use cases:

  • External preconditions: a controller (e.g., cert- manager, service mesh) sets the readiness gate condition once an external system is ready (certificate issued, sidecar proxy configured).
  • Cluster-wide rollout coordination: a custom controller marks Pods as Ready only when a global state allows it (e.g., a canary rollout controller that holds traffic until the canary is validated).
  • Pod-specific gates: a test runner marks the Pod as Ready only after running integration tests.
stateDiagram-v2
    [*] --> Init: created
    Init --> Running: init containers succeed
    Running --> Pending: readiness gate False
    Pending --> Ready: readiness gate True + readiness probe success
    Ready --> NotReady: readiness gate False or readiness probe fails
    NotReady --> Ready: condition met

The Pod transitions to Ready only when:

  • All readiness probes (per-container) succeed.
  • All readiness gates have status True.
  • The Initialized condition is True.

Init containers vs readiness gates

Both gate traffic; the difference is when they act:

Init containerReadiness gate
When it actsBefore main containers startAfter main containers start
What gatesPod startPod readiness
How it’s setThe container itself (must exit 0)External actor patches Pod status
Failure behaviourPod stuck in PendingPod Running but not Ready (excluded from Endpoints)

Use init containers for setup that must complete before the workload starts (migrations, config generation, dependency waiting).

Use readiness gates for external preconditions that cannot be expressed as init containers (certificate issued by cert-manager, sidecar proxy configured by service mesh).

Production patterns

Multi-step setup with init containers:

initContainers:
- name: 01-fetch-config
  image: config-fetcher:1.0
- name: 02-validate
  image: validator:1.0
- name: 03-warm-cache
  image: cache-warmer:1.0
- name: 04-migrate
  image: migrate/migrate:4

Numbered names make the order explicit in the manifest.

Readiness gate for cert-manager:

spec:
  readinessGates:
  - conditionType: cert-manager.io/issuer-ready

cert-manager sets this condition to True once the certificate is issued and ready. The Pod is excluded from Endpoints until the certificate is ready.

Readiness gate for service mesh:

spec:
  readinessGates:
  - conditionType: istio.io/warmup-complete

The service mesh control plane sets this condition once the proxy is configured and warm.

Cross-course references

  • The Linux course part XXII-Linux-NetTroubleshoot covers dependency waiting patterns; init containers are the cluster-level equivalent.
  • The Ansible course part XX-Ansible-SSH covers setup tasks; init containers are the cluster-level equivalent.
  • The Docker course part XXIX-Docker-Build covers image layers and build steps; init containers run additional images sequentially.

Quiz

Knowledge check · 4 questions

  1. Q1. Two init containers in the same Pod run in what order?

  2. Q2. A readiness gate allows an external actor to keep a Pod from being Ready (and excluded from Endpoints) until a precondition is met.

  3. Q3. A Pod has four init containers. The first three succeed; the fourth runs but always exits with code 1 after 30 seconds. Diagnose.

    Init containers: 01-fetch-config (succeeds), 02-validate (succeeds), 03-migrate (succeeds), 04-warm-cache (fails with exit code 1 after 30s). The 04-warm-cache container runs a script that fetches data from an external API and caches it. The Pod is stuck in Pending.

  4. Q4. When is the right tool a readiness gate (rather than an init container) for a precondition?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Number init container names to make order explicit. 01-fetch, 02-validate, 03-migrate reads better than arbitrary names.
  • Keep init containers simple and idempotent. Complex logic in init containers is a maintenance burden.
  • Use readiness gates for external preconditions. When the gate is set by a controller (cert-manager, service mesh), not by the Pod itself.
  • Document the init chain in the runbook. Each init container has a purpose; operators need to know it.
  • Avoid chaining many init containers. If you have 5+ init containers, consider a Job or a setup Pod that completes first.