KubernetesXI · Init Containers and SidecarsInit containers and sidecars
Init container ordering and readiness gates
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
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:
fetch-configdownloads configuration to/config.validate-configreads/config/app.confand validates it.migrateruns the database migration.appstarts 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
Initializedcondition is True.
Init containers vs readiness gates
Both gate traffic; the difference is when they act:
| Init container | Readiness gate | |
|---|---|---|
| When it acts | Before main containers start | After main containers start |
| What gates | Pod start | Pod readiness |
| How it’s set | The container itself (must exit 0) | External actor patches Pod status |
| Failure behaviour | Pod stuck in Pending | Pod 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-NetTroubleshootcovers dependency waiting patterns; init containers are the cluster-level equivalent. - The Ansible course part
XX-Ansible-SSHcovers setup tasks; init containers are the cluster-level equivalent. - The Docker course part
XXIX-Docker-Buildcovers image layers and build steps; init containers run additional images sequentially.
Quiz
Knowledge check · 4 questions
Q1. Two init containers in the same Pod run in what order?
Q2. A readiness gate allows an external actor to keep a Pod from being Ready (and excluded from Endpoints) until a precondition is met.
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.
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-migratereads 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.