Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Init Containers et Sidecars : préparer et accompagner vos Pods

20 min de lecture

logo kubernetes

Votre application a besoin de télécharger une config avant de démarrer ? Ou de collecter ses logs vers un système centralisé ? Les init containers et les sidecars répondent à ces besoins sans modifier votre code applicatif.

Ce guide vous montre comment utiliser ces deux patterns, quand les choisir, et comment éviter les erreurs courantes.

Prérequis : concepts des Pods Kubernetes et un cluster fonctionnel.

  • Créer un init container qui prépare des données avant le démarrage
  • Configurer un sidecar qui tourne en parallèle de votre application
  • Distinguer le pattern sidecar du sidecar natif Kubernetes
  • Comprendre quand utiliser (et quand éviter) chaque approche
  • Diagnostiquer les problèmes avec les bonnes commandes

Avant d’entrer dans les détails, rappelons pourquoi init containers et sidecars sont utiles : tous les conteneurs d’un même Pod partagent :

RessourceCe qui est partagé
RéseauMême adresse IP, même espace réseau (localhost fonctionne entre conteneurs)
VolumesMêmes volumes montés selon la configuration
SchedulingMême nœud, même unité de déploiement
Cycle de vieDémarrent et s’arrêtent ensemble

C’est ce partage qui rend les patterns init container et sidecar possibles et puissants.

Un init container est un conteneur qui s’exécute avant les conteneurs principaux du Pod. Il doit se terminer avec succès pour que l’application démarre.

Les init containers ont un comportement strict :

  • Ils s’exécutent séquentiellement, dans l’ordre de déclaration
  • Chaque init container doit réussir (exit code 0) avant le suivant
  • En cas d’échec, le kubelet relance l’init container selon la restartPolicy
  • Les conteneurs applicatifs ne démarrent qu’après la réussite de tous les init containers
Cas d’usageExemple concret
Télécharger des fichiersRécupérer une config depuis S3 ou un dépôt Git
Attendre un serviceVérifier que MySQL répond avant de lancer l’app
Initialiser des donnéesAppliquer des migrations de base de données
Préparer le filesystemCréer des répertoires, décompresser des archives

Cet init container écrit un fichier de configuration que le conteneur principal utilise :

init-container-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: init-download
image: busybox:1.36
command: ['sh', '-c', 'echo "Config chargée à $(date)" > /data/config.txt && sleep 2']
volumeMounts:
- name: shared-data
mountPath: /data
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'cat /data/config.txt && sleep 3600']
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}
Fenêtre de terminal
kubectl apply -f init-container-demo.yaml
Fenêtre de terminal
kubectl get pod init-demo -w

Sortie pendant l’initialisation :

NAME READY STATUS RESTARTS AGE
init-demo 0/1 Init:0/1 0 2s
init-demo 0/1 PodInitializing 0 4s
init-demo 1/1 Running 0 5s

Le statut Init:0/1 indique que l’init container n’est pas encore terminé.

Fenêtre de terminal
kubectl logs init-demo -c app

Sortie attendue :

Config chargée à Sun Mar 22 08:44:45 UTC 2026

Le conteneur principal a bien lu le fichier créé par l’init container.

Un cas très courant est d’attendre qu’un service soit disponible :

init-wait-service.yaml
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command: ['sh', '-c', 'until nc -z mysql 3306; do echo "Attente MySQL..."; sleep 2; done']
containers:
- name: app
image: nginx:alpine

L’init container boucle jusqu’à ce que MySQL réponde sur le port 3306.

Sans limite de temps, un init container peut bloquer indéfiniment :

command: ['sh', '-c', 'timeout 60 sh -c "until nc -z mysql 3306; do sleep 2; done"']

Il existe deux réalités qu’il faut distinguer :

Historiquement, un sidecar désigne simplement un second conteneur dans spec.containers qui accompagne le conteneur principal. C’est un pattern d’architecture, pas une fonctionnalité Kubernetes.

spec:
containers:
- name: app
image: myapp:1.0
- name: log-collector # Sidecar "classique"
image: fluentbit:2.0

Les deux conteneurs démarrent ensemble, sans ordre garanti.

Depuis Kubernetes v1.29, une fonctionnalité dédiée permet de déclarer des sidecars avec un cycle de vie contrôlé. Un sidecar natif est un init container avec restartPolicy: Always.

spec:
initContainers:
- name: log-agent
image: fluentbit:2.0
restartPolicy: Always # C'est un sidecar natif !
AspectPattern classiqueSidecar natif
Déclarationspec.containersspec.initContainers avec restartPolicy: Always
Ordre de démarragePas garantiDémarre avant le conteneur principal
ArrêtPas d’ordreS’arrête après le conteneur principal
RedémarragePeut crasher le PodRedémarre indépendamment

Le sidecar lit les logs écrits par l’application principale dans un fichier partagé :

sidecar-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'while true; do echo "$(date) - Requête traitée" >> /var/log/app.log; sleep 5; done']
volumeMounts:
- name: logs
mountPath: /var/log
- name: log-collector
image: busybox:1.36
command: ['sh', '-c', 'tail -f /var/log/app.log']
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
emptyDir: {}
Fenêtre de terminal
kubectl apply -f sidecar-demo.yaml
Fenêtre de terminal
kubectl get pod sidecar-demo

Sortie :

NAME READY STATUS RESTARTS AGE
sidecar-demo 2/2 Running 0 15s

2/2 Running confirme que les deux conteneurs tournent.

Fenêtre de terminal
kubectl logs sidecar-demo -c log-collector

Sortie :

Sun Mar 22 08:45:07 UTC 2026 - Requête traitée
Sun Mar 22 08:45:12 UTC 2026 - Requête traitée

Les sidecars natifs offrent un meilleur contrôle du cycle de vie :

native-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: native-sidecar
spec:
initContainers:
- name: log-agent
image: busybox:1.36
restartPolicy: Always # Sidecar natif !
command: ['sh', '-c', 'tail -f /var/log/app.log 2>/dev/null || sleep infinity']
volumeMounts:
- name: logs
mountPath: /var/log
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'while true; do echo "$(date) - Log" >> /var/log/app.log; sleep 5; done']
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
emptyDir: {}

Avantages du sidecar natif :

  • Démarre avant le conteneur principal (comme un init container)
  • Tourne pendant toute la vie du Pod (comme un sidecar classique)
  • S’arrête proprement après le conteneur principal
  • Peut redémarrer sans faire crasher le Pod entier
BesoinInit containerSidecar
Préparer des fichiers avant démarrage✅ Oui❌ Non
Attendre une dépendance✅ Oui (avec timeout)⚠️ Rarement
Collecter des logs pendant la vie du Pod❌ Non✅ Oui
Proxy réseau local au Pod❌ Non✅ Oui
Exécuter une migration ponctuelle✅ Oui❌ Non
Synchroniser des fichiers en continu❌ Non✅ Oui
Exporter des métriques❌ Non✅ Oui
PatternExemple
Log collectorFluent Bit, Filebeat → Elasticsearch/Loki
ProxyEnvoy, Istio pour le service mesh
SyncGit-sync pour fichiers de config
MonitoringExporter des métriques Prometheus

Un sidecar n’est pas toujours la bonne solution :

SituationPourquoi éviterAlternative
Fonction mutualisableUn sidecar par Pod = N instancesDaemonSet (1 par nœud)
Besoin uniquement au buildPas besoin en runtimeJob CI/CD
Fonction indépendante du PodCouplage inutileDeployment séparé
Logs vers stdoutLe nœud collecte déjàAucun sidecar nécessaire
Proxy cluster-wideDuplication massiveIngress ou service mesh

Chaque conteneur supplémentaire consomme des ressources :

  • CPU et mémoire : l’init container allonge le démarrage, le sidecar consomme en continu
  • I/O disque : si le sidecar écrit beaucoup (logs, métriques)
  • Bande passante : si le sidecar envoie des données vers l’extérieur
initContainers:
- name: init-download
image: busybox:1.36
resources:
requests:
cpu: "50m"
memory: "32Mi"
limits:
cpu: "100m"
memory: "64Mi"

Déclarez aussi les resources de vos sidecars pour éviter les surprises en production.

Un Pod peut avoir les deux :

combined-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: full-stack
spec:
initContainers:
- name: download-config
image: busybox:1.36
command: ['sh', '-c', 'echo "DB_HOST=mysql" > /config/env']
volumeMounts:
- name: config
mountPath: /config
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'cat /config/env && while true; do echo "$(date) - Request" >> /logs/app.log; sleep 5; done']
volumeMounts:
- name: config
mountPath: /config
- name: logs
mountPath: /logs
- name: log-shipper
image: busybox:1.36
command: ['sh', '-c', 'tail -f /logs/app.log']
volumeMounts:
- name: logs
mountPath: /logs
volumes:
- name: config
emptyDir: {}
- name: logs
emptyDir: {}

Flux d’exécution :

  1. download-config (init) prépare la configuration
  2. app et log-shipper démarrent ensemble
  3. log-shipper transmet les logs en continu
Anti-patternConséquenceSolution
Attendre sans timeoutPod bloqué indéfinimentAjouter timeout à la commande
Logique métier lourde en initDémarrage très longExternaliser dans un Job
Port ouvert = service prêtFaux positifsTest fonctionnel léger
Sidecar pour fonction mutualisableGaspillage de ressourcesDaemonSet
chmod/chown en init containerSymptôme de mauvaise configUtiliser securityContext
Oublier resources sur les sidecarsConsommation non contrôléeDéclarer requests/limits
Plusieurs conteneurs = plus de couplageMaintenance complexeÉvaluer si vraiment nécessaire
  1. Voir l’état du Pod et des conteneurs

    Fenêtre de terminal
    kubectl get pod mon-pod -o wide
    kubectl get pod mon-pod -o yaml | grep -A 30 "containerStatuses"
  2. Examiner les détails des init containers

    Fenêtre de terminal
    kubectl describe pod mon-pod | grep -A 30 "Init Containers"
  3. Lire les logs d’un init container

    Fenêtre de terminal
    kubectl logs mon-pod -c nom-init-container
    kubectl logs mon-pod -c nom-init-container --previous # Si redémarré
  4. Lire les logs d’un sidecar

    Fenêtre de terminal
    kubectl logs mon-pod -c nom-sidecar
  5. Voir les événements récents

    Fenêtre de terminal
    kubectl get events --sort-by=.lastTimestamp | grep mon-pod
SymptômeCause probableSolution
Init:0/1 qui persisteInit container bloqué ou en échecVérifier les logs : kubectl logs mon-pod -c init-xxx
Init:CrashLoopBackOffCommande qui échoue (exit code ≠ 0)Corriger la commande ou l’image
Init:ImagePullBackOffImage introuvableVérifier le nom et le registry
READY 1/2Un des conteneurs ne démarre paskubectl describe pod pour les événements
Sidecar natif qui ne tourne pasrestartPolicy: Always oubliéAjouter le champ dans l’init container
Fenêtre de terminal
kubectl describe pod init-demo
Events:
Type Reason Age Message
---- ------ ---- -------
Normal Scheduled 1m Successfully assigned default/init-demo to node1
Normal Pulling 1m Pulling image "busybox:1.36"
Normal Pulled 55s Successfully pulled image
Normal Created 55s Created container init-download
Normal Started 55s Started container init-download
Normal Pulled 50s Container init-download completed successfully
Normal Created 50s Created container app
Normal Started 50s Started container app

En examen, voici le workflow efficace :

Fenêtre de terminal
# 1. Créer le manifest
kubectl run mypod --image=nginx --dry-run=client -o yaml > pod.yaml
# 2. Éditer pour ajouter initContainers (même niveau que containers)
vim pod.yaml
# 3. Appliquer
kubectl apply -f pod.yaml
# 4. Vérifier l'état
kubectl get pod mypod -w
# 5. Voir les logs de l'init container
kubectl logs mypod -c init-container-name
# 6. Voir les logs du conteneur principal
kubectl logs mypod -c nginx
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
initContainers: # Même niveau que containers
- name: init-xxx
image: busybox:1.36
command: ['sh', '-c', 'echo done']
volumeMounts:
- name: data
mountPath: /data
containers:
- name: app
image: nginx
volumeMounts:
- name: data
mountPath: /data
volumes: # Partagé entre tous les conteneurs
- name: data
emptyDir: {}
  1. Init container : s’exécute et se termine AVANT le conteneur principal
  2. Sidecar classique : conteneur dans containers, tourne EN PARALLÈLE
  3. Sidecar natif : init container avec restartPolicy: Always (stable v1.33)
  4. Les init containers s’exécutent séquentiellement, chacun doit réussir
  5. Les init containers ne supportent pas les probes ni lifecycle hooks
  6. Un port TCP ouvert ne garantit pas qu’un service est prêt
  7. Les conteneurs d’un Pod partagent réseau et volumes
  8. Chaque conteneur supplémentaire consomme des ressources
  9. Un sidecar qui peut être mutualisé devrait être un DaemonSet
  10. Commandes clés : kubectl logs -c, kubectl describe, kubectl get events

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn