Un pod Kubernetes peut définir des conteneurs qui s’exécutent avant le conteneur principal, jusqu’à leur terminaison complète, avant que ce dernier ne démarre. Ce mécanisme, les init containers, résout un problème structurel simple : certaines étapes de préparation doivent être terminées, pas seulement démarrées, avant que l’application ne puisse tourner en toute sécurité.
L’exécution séquentielle, strictement dans l’ordre
Les init containers d’un pod s’exécutent un par un, dans l’ordre déclaré, chacun devant se terminer avec succès avant que le suivant ne démarre. Le conteneur principal ne démarre qu’une fois tous les init containers terminés : un échec de l’un d’eux met le pod en attente, sans jamais lancer le conteneur applicatif sur une préparation incomplète.
spec:
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z postgres 5432; do sleep 2; done']
- name: run-migrations
image: myapp-migrate
command: ['./migrate.sh']
containers:
- name: app
image: myapp
Ce que ça résout que les probes ne résolvent pas
Une sonde readiness vérifie qu’un conteneur déjà démarré est prêt à recevoir du trafic, mais le conteneur principal a déjà démarré à ce moment, potentiellement avant que sa dépendance ne soit prête (une base de données pas encore accessible, une migration de schéma pas encore appliquée). L’init container déplace cette attente avant le démarrage du conteneur applicatif lui-même : l’application ne voit jamais un état intermédiaire non préparé, parce qu’elle ne démarre tout simplement pas avant.
Le piège classique : un init container qui ne termine jamais
Un init container en boucle d’attente sans mécanisme de sortie propre (until nc -z ... ; done, sans jamais de timeout) bloque indéfiniment le pod si la dépendance attendue ne devient jamais disponible, sans jamais déclencher de CrashLoopBackOff visible côté conteneur principal puisque celui-ci n’a jamais démarré. Le pod reste en Init:0/2, un état qui se diagnostique différemment d’un CrashLoopBackOff classique : kubectl describe pod reste la première commande, mais les logs à consulter sont ceux de l’init container, pas du conteneur principal.
# Un pod bloqué en Init:X/Y n'a jamais atteint
# le conteneur principal, les logs à lire sont ailleurs
kubectl logs my-pod -c wait-for-db
Le sidecar natif : un init container qui ne se termine jamais, à dessein
Depuis Kubernetes 1.29, un init container peut déclarer restartPolicy: Always, ce qui change fondamentalement son comportement : il démarre avant le conteneur principal comme un init container classique, mais continue de tourner en parallèle une fois celui-ci lancé, redémarrant automatiquement s’il meurt, exactement comme un conteneur du pod principal.
spec:
initContainers:
- name: log-shipper
image: fluent-bit
restartPolicy: Always # devient un sidecar natif, tourne en continu
containers:
- name: app
image: myapp
Ce sidecar natif garantit un ordre de démarrage que le service mesh injecté par webhook (voir l’article Istio vs Linkerd) ne garantissait pas nativement avant cette fonctionnalité : le sidecar de log-shipping ou de proxy réseau démarre et devient prêt avant le conteneur applicatif, éliminant une classe de bugs de démarrage où l’application tente d’utiliser un sidecar pas encore opérationnel.
À retenir
Les init containers s’exécutent séquentiellement jusqu’à terminaison complète avant le conteneur principal, déplaçant une attente de dépendance avant le démarrage applicatif plutôt que de la gérer via une probe après coup. Un init container en boucle sans sortie propre bloque le pod en Init:X/Y, un état à diagnostiquer via ses propres logs, distinct d’un CrashLoopBackOff classique. Le sidecar natif (restartPolicy: Always, Kubernetes 1.29+) garantit un ordre de démarrage pour un conteneur qui doit tourner en continu, une primitive qui compte dès qu’une migration Kubernetes doit fiabiliser l’ordre de démarrage d’un pod à plusieurs conteneurs.