## Introduction

Les conteneurs d'initialisation Kubernetes échouent souvent pour des raisons qui ne sont pas évidentes à partir du seul statut du pod. Un opérateur voit `Init:0/1` ou `Init:Error` et a besoin d'un chemin fiable du symptôme à la résolution. Ce guide fournit des étapes de dépannage pratiques, pilotées par commandes, pour les conteneurs d'initialisation Kubernetes, avec des exemples concrets, des sorties attendues et une vérification de la récupération. Il s'adresse aux développeurs, ingénieurs DevOps et équipes plateforme qui exécutent Kubernetes en production ou en préproduction. Nous couvrons l'inventaire des versions et de l'environnement, la configuration sûre, la vérification et le diagnostic, les modes de défaillance et la récupération, ainsi qu'une liste de contrôle opérationnelle. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier le résultat et documenter la récupération avant qu'un incident ne force une décision.

## Inventaire des versions et de l'environnement

Avant de dépanner une défaillance de conteneur d'initialisation, rassemblez des informations précises sur votre cluster Kubernetes et le pod affecté. Cela réduit les fausses hypothèses et circonscrit l'espace du problème.

### Vérifier la version du cluster et les dépréciations d'API

```bash
kubectl version --short
```
Sortie attendue (exemple) :
```
Client Version: v1.28.2
Server Version: v1.28.2
```
Si le conteneur d'initialisation utilise une API bêta qui a été supprimée dans la version du serveur (par exemple, `extensions/v1beta1` supprimée en 1.16), le pod ne pourra pas être créé. Confirmez avec :
```bash
kubectl explain pod.spec.initContainers | head -20
```
Si la commande renvoie `error: the server doesn't have a resource type "pod"` ou similaire, vérifiez la connectivité au cluster et les informations d'identification.

### Identifier le pod, l'espace de noms et les noms des conteneurs d'initialisation

```bash
kubectl get pods -n <namespace> -o wide
```
Exemple de sortie :
```
NAME                READY   STATUS     RESTARTS   AGE   IP           NODE
web-app-6d4b8c-abc  0/1     Init:0/2   0          5m    10.244.2.5   node-1
```
La colonne `STATUS` montre l'état du conteneur d'initialisation : `Init:0/2` signifie que 0 conteneur d'initialisation sur 2 est terminé. Pour lister les noms des conteneurs d'initialisation dans un pod :
```bash
kubectl get pod web-app-6d4b8c-abc -n <namespace> -o jsonpath='{.spec.initContainers[*].name}'
```
Sortie attendue :
```
init-db init-migrate
```

### Inspecter les événements du pod pour un premier signal

```bash
kubectl describe pod web-app-6d4b8c-abc -n <namespace>
```
Recherchez les événements en bas. Exemple :
```
Events:
  Type     Reason     Age   From               Message
  ----     ------     ----  ----               -------
  Normal   Scheduled  5m    default-scheduler  Successfully assigned default/web-app-6d4b8c-abc to node-1
  Warning  Failed     4m    kubelet            Error: failed to create containerd task: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "bootstrap.sh": executable file not found in $PATH: unknown
```
Cet événement pointe immédiatement vers un exécutable manquant dans l'image du conteneur d'initialisation.

## Chemin de configuration sûr

Lorsque vous modifiez une configuration, capturez toujours l'état actuel avec horodatage, puis appliquez le plus petit changement réversible. Ne mettez jamais de secrets directement dans les manifestes ; utilisez les Secrets Kubernetes ou des stockages de secrets externes.

### Capturer le manifeste actuel et la somme de contrôle

```bash
kubectl get pod web-app-6d4b8c-abc -n <namespace> -o yaml > pod-before.yaml
shasum -a 256 pod-before.yaml
```
Exemple de sortie :
```
e1c7f8f2b6a4d...  pod-before.yaml
```

### Mauvaise configuration courante : commande ou arguments incorrects

De nombreux conteneurs d'initialisation échouent parce que la `command` ou les `args` remplacent incorrectement le point d'entrée par défaut de l'image. Par exemple, ce manifeste vise à attendre une base de données mais utilise incorrectement une commande shell :

```yaml
initContainers:
  - name: init-mysql
    image: busybox:1.36
    command: ["until nc -z mysql 3306; do sleep 2; done"]
```
La commande est une chaîne unique, mais `command` attend un tableau. Il faudrait :
```yaml
initContainers:
  - name: init-mysql
    image: busybox:1.36
    command: ['sh', '-c', 'until nc -z mysql 3306; do echo waiting for mysql; sleep 2; done']
```
Après correction, appliquez le changement :
```bash
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web-app -n <namespace> --timeout=120s
```
Sortie attendue en cas de succès :
```
deployment "web-app" successfully rolled out
```

### Variables d'environnement et secrets

Utilisez des références de secret plutôt que des valeurs littérales :
```yaml
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-secret
        key: password
```
Vérifiez que le secret existe avant la création du pod :
```bash
kubectl get secret db-secret -n <namespace>
```
S'il manque, le conteneur d'initialisation peut échouer avec `CreateContainerConfigError`. Voir Modes de défaillance.

### Notes de compatibilité de version

- Kubernetes 1.20+ prend en charge les conteneurs éphémères pour le débogage, mais les conteneurs d'initialisation sont standard.
- Si vous utilisez `restartPolicy: Always` dans un pod avec des conteneurs d'initialisation, les conteneurs d'initialisation en échec redémarrent selon la politique.

## Vérification et diagnostic

Cette section montre des commandes de diagnostic pas à pas pour identifier la défaillance exacte.

### Obtenir les journaux du conteneur d'initialisation

```bash
kubectl logs web-app-6d4b8c-abc -n <namespace> -c init-mysql --tail=50
```
Si le conteneur d'initialisation a planté et redémarré, utilisez `--previous` :
```bash
kubectl logs web-app-6d4b8c-abc -n <namespace> -c init-mysql --previous
```
Exemple de journal pour un refus de connexion :
```
/bin/sh: nc: not found
```
Cela indique que `nc` est manquant dans busybox. Utilisez `busybox:1.36` avec `nc` via `busybox-extras` ou une autre image comme `alpine/socat`.

### Vérifier les codes de sortie et la raison de terminaison

```bash
kubectl get pod web-app-6d4b8c-abc -n <namespace> -o jsonpath='{.status.initContainerStatuses[?(@.name=="init-mysql")].state}'
```
Exemple de sortie :
```json
{"terminated":{"exitCode":127,"reason":"ContainerCannotRun","message":"exec: \"nc\": executable file not found in $PATH","startedAt":"...","finishedAt":"...","containerID":"..."}}
```
Codes de sortie courants :
- `126` : permission refusée ou commande non exécutable
- `127` : commande introuvable
- `137` : SIGKILL (OOM ou échec de sonde de vie)
- `1` : erreur applicative générale

### Inspecter les limites de ressources et l'état du nœud

Si le conteneur d'initialisation reste bloqué dans `Init:0/1` pendant longtemps, vérifiez s'il est OOMKilled :
```bash
kubectl describe pod web-app-6d4b8c-abc -n <namespace> | grep -A5 'State'
```
Exemple :
```
State:          Waiting
  Reason:       CrashLoopBackOff
Last State:     Terminated
  Reason:       OOMKilled
  Exit Code:    137
```
Augmentez la limite de mémoire ou optimisez le conteneur d'initialisation.

### Déboguer avec des conteneurs éphémères (K8s 1.23+)

Si le conteneur d'initialisation ne peut pas démarrer du tout, vous pouvez exécuter un conteneur de débogage éphémère pour inspecter l'environnement :
```bash
kubectl debug -it web-app-6d4b8c-abc -n <namespace> --image=busybox:1.36 --target=init-mysql
```
Testez ensuite la connectivité manuellement.

## Modes de défaillance et récupération

Cette section couvre des modes de défaillance spécifiques, leurs causes et les étapes de récupération.

### Défaillance : `Init:Error` ou `Init:CrashLoopBackOff`

Cause : le processus du conteneur d'initialisation se termine avec un code non nul à plusieurs reprises.
Récupération :
1. Obtenez les journaux et le code de sortie comme ci-dessus.
2. Corrigez la commande, le bogue de script ou la dépendance manquante.
3. Appliquez le correctif et forcez un nouveau déploiement si nécessaire :
```bash
kubectl rollout restart deployment/web-app -n <namespace>
```
4. Surveillez :
```bash
kubectl get pods -n <namespace> -w
```

### Défaillance : `Init:CreateContainerConfigError`

Cause : la ConfigMap ou le Secret référencé n'existe pas, ou problème de permissions.
Exemple d'événement :
```
Warning  Failed     4s    kubelet            Error: secret "db-secret" not found
```
Récupération :
```bash
kubectl create secret generic db-secret --from-literal=password='S3cureP@ss' -n <namespace>
# ou appliquez le manifeste du secret
kubectl apply -f db-secret.yaml
```
Supprimez ensuite le pod pour redémarrer les conteneurs d'initialisation :
```bash
kubectl delete pod web-app-6d4b8c-abc -n <namespace>
```

### Défaillance : `Init:ImagePullBackOff`

Cause : nom d'image incorrect, balise, authentification ou politique réseau.
Vérifiez les événements :
```bash
kubectl describe pod web-app-6d4b8c-abc -n <namespace> | grep -A5 'Events'
```
Exemple :
```
Warning  Failed     10s   kubelet            Failed to pull image "myregistry/init:v2": rpc error: code = NotFound desc = failed to pull and unpack image "myregistry/init:v2": failed to resolve reference "myregistry/init:v2": not found
```
Récupération : corrigez le nom/la balise de l'image, créez un imagePullSecret :
```bash
kubectl create secret docker-registry regcred --docker-server=myregistry --docker-username=user --docker-password=pass --docker-email=user@example.com
```
Ajoutez `imagePullSecrets` à la spécification du pod.

### Défaillance : le conteneur d'initialisation se termine mais le conteneur d'application échoue

Ce n'est pas une défaillance du conteneur d'initialisation en soi, mais vérifiez que le conteneur d'initialisation a réussi :
```bash
kubectl get pod web-app-6d4b8c-abc -n <namespace> -o jsonpath='{.status.initContainerStatuses[*].state.terminated.exitCode}'
```
Si la sortie est `0`, les conteneurs d'initialisation ont réussi ; dépannez le conteneur d'application séparément.

## Liste de contrôle opérationnelle

Utilisez cette liste avant et après tout changement sur les conteneurs d'initialisation.

### Avant le changement
- [ ] Confirmer la version du cluster et la compatibilité de l'API.
- [ ] Capturer le manifeste actuel du pod avec horodatage : `kubectl get pod <name> -o yaml > pod-$(date +%Y%m%d%H%M%S).yaml`
- [ ] Identifier les noms des conteneurs d'initialisation : `kubectl get pod <name> -o jsonpath='{.spec.initContainers[*].name}'`
- [ ] Noter l'état actuel : `kubectl get pods -n <namespace>`
- [ ] Vérifier que tous les secrets/configmaps référencés existent.

### Après le changement
- [ ] Appliquer le changement : `kubectl apply -f updated-manifest.yaml`
- [ ] Surveiller le déploiement : `kubectl rollout status deployment/<deployment> --timeout=120s`
- [ ] Vérifier que le nouveau pod est passé à `Running` avec tous les conteneurs d'initialisation terminés :
```bash
kubectl wait --for=condition=Initialized pod/web-app-6d4b8c-abc -n <namespace> --timeout=60s
```
Attendu : `pod/web-app-6d4b8c-abc condition met`
- [ ] Tester le point de terminaison de l'application ou sa fonctionnalité.
- [ ] Documenter le mode de défaillance, la cause et le correctif dans le runbook.

### Exemple d'entrée de runbook
```
Date : 2025-03-15
Problème : Le conteneur d'initialisation init-mysql a quitté avec le code 127, nc introuvable.
Correctif : Changement de l'image de busybox:1.35 à alpine/socat:1.7.4.3 et ajustement de la commande.
Vérification : le pod est passé à Running en 45 s, le journal montre "waiting for mysql" puis succès.
```

## Conclusion

Le dépannage des conteneurs d'initialisation Kubernetes nécessite une approche méthodique : rassembler les détails de version et d'environnement, inspecter les événements et les journaux, vérifier les codes de sortie et appliquer des correctifs minimaux avec vérification. Les exemples de ce guide fournissent un modèle pour les défaillances courantes telles que les binaires manquants, les mauvaises commandes, les secrets absents et les erreurs d'extraction d'image. Observez toujours avant de modifier, protégez les informations d'identification et définissez la vérification de la récupération avant un incident. Choisissez une vérification à faible risque de ce guide, enregistrez l'état actuel, exécutez le contrôle documenté, comparez le résultat et examinez les dépendances telles que le cycle de vie du pod et la configuration. Un flux de travail fiable rend la défaillance visible et limite les changements à la ressource prévue.