## Introduction

Kubernetes est l'orchestrateur de conteneurs de facto, mais les problèmes liés aux images restent l'une des sources les plus courantes d'échecs de déploiement. Un nom d'image mal configuré, des identifiants de registre manquants ou une architecture incompatible peuvent entraîner des boucles de crash ou empêcher complètement le démarrage des pods. Pour les développeurs et les ingénieurs DevOps, diagnostiquer et corriger rapidement ces problèmes est essentiel pour maintenir la fiabilité des services et la vitesse de livraison.

Ce guide fournit une approche pratique pour dépanner les problèmes d'images Kubernetes. Il couvre l'inventaire de l'environnement, les pratiques de configuration sécuritaires, les commandes de vérification, les modes de défaillance courants et les étapes de récupération. Chaque section inclut des commandes concrètes et les sorties attendues. À la fin, vous disposerez d'une méthodologie reproductible pour résoudre les problèmes liés aux images dans vos clusters.

## Inventaire des versions et de l'environnement

Avant de commencer le dépannage, établissez les versions de Kubernetes et du runtime de conteneurs, la topologie du cluster et les charges de travail affectées. Cette délimitation évite les efforts inutiles et permet d'identifier les particularités liées aux versions.

### Collecter les versions du cluster et du runtime

Exécutez les commandes suivantes depuis une machine avec kubectl configuré :

```bash
kubectl version --short
kubectl get nodes -o wide
```

La sortie attendue affiche les versions client et serveur, ainsi que les détails des nœuds, y compris le runtime de conteneurs (par exemple, containerd, CRI-O) et l'image du système d'exploitation. Par exemple :

```
Client Version: v1.27.3
Server Version: v1.27.3
NAME        STATUS   ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
node-1      Ready    control-plane   10d   v1.27.3   10.0.0.1      <none>        Ubuntu 22.04.2 LTS   5.15.0-76-generic   containerd://1.7.1
node-2      Ready    <none>          10d   v1.27.3   10.0.0.2      <none>        Ubuntu 22.04.2 LTS   5.15.0-76-generic   containerd://1.7.1
```

Pour plus de détails sur un nœud, décrivez-le :

```bash
kubectl describe node <node-name>
```

Recherchez les champs « Container Runtime Version » et « Kubelet Version ». Exemple d'extrait :

```
System Info:
  Machine ID:                 9b2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d
  System UUID:                12345678-1234-1234-1234-123456789abc
  Boot ID:                    a1b2c3d4-e5f6-7890-abcd-ef1234567890
  Kernel Version:             5.15.0-76-generic
  OS Image:                   Ubuntu 22.04.2 LTS
  Operating System:           linux
  Architecture:               amd64
  Container Runtime Version:  containerd://1.7.1
  Kubelet Version:            v1.27.3
  Kube-Proxy Version:         v1.27.3
```

### Identifier les charges de travail et les images affectées

Listez les pods dans tous les espaces de noms avec les informations sur les images :

```bash
kubectl get pods -A -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,IMAGES:.spec.containers[*].image
```

Cela permet d'identifier précisément les pods en échec et les images qu'ils référencent. Exemple de sortie :

```
NAMESPACE   NAME                     STATUS             IMAGES
default     web-6d4b8c9f5-abcde      ImagePullBackOff   nginx:1.21.6
default     api-7f8b9c6d5-xyzab     CrashLoopBackOff   myregistry.com/myapp:2.3.1
kube-system coredns-5d78c9d8f-12345 Running            registry.k8s.io/coredns/coredns:v1.10.1
```

### Vérification des prérequis

Assurez-vous de disposer de :

- kubectl installé et configuré avec les autorisations appropriées.
- Accès au registre de conteneurs (par exemple, Docker Hub, registre privé) pour tirer les images à des fins de test.
- Capacité à inspecter les journaux et les événements.

Si vous soupçonnez des problèmes de connectivité au registre, testez depuis l'intérieur du cluster (par exemple, en utilisant un pod de débogage) ou depuis un nœud si possible.

## Chemin de configuration sécuritaire

Lors de la correction des problèmes d'images, il est crucial d'apporter des modifications de manière incrémentale et sécuritaire. Évitez de modifier directement les charges de travail en production sans test. Utilisez des déploiements canaris, des mises à jour progressives ou recréez les pods de manière contrôlée.

### Corriger les références d'images

Les erreurs courantes d'images incluent les fautes de frappe, les mauvaises étiquettes ou les préfixes de registre manquants. Pour corriger, modifiez le déploiement :

```bash
kubectl edit deployment <deployment-name> -n <namespace>
```

Ou appliquez un correctif :

```bash
kubectl patch deployment <deployment-name> -n <namespace> --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.21.6"}]'
```

Après l'application du correctif, le déploiement se déclenche automatiquement. Surveillez avec :

```bash
kubectl rollout status deployment/<deployment-name> -n <namespace>
```

Attendu : `deployment "<deployment-name>" successfully rolled out`

### Gérer les identifiants de registre

Si les pods échouent avec `ImagePullBackOff` ou `ErrImagePull` en raison d'une authentification, assurez-vous qu'un secret de type `docker-registry` existe et est référencé.

Créez un secret à partir de la configuration Docker existante ou des identifiants :

```bash
kubectl create secret docker-registry regcred \
  --docker-server=myregistry.example.com \
  --docker-username=myuser \
  --docker-password=mypassword \
  --docker-email=myuser@example.com \
  -n default
```

Ajoutez ensuite `imagePullSecrets` à la spécification du pod ou au compte de service. Corrigez le compte de service :

```bash
kubectl patch serviceaccount default -n default -p '{"imagePullSecrets": [{"name": "regcred"}]}'
```

Vérifiez que le secret existe :

```bash
kubectl get secret regcred -n default -o yaml
```

La sortie attendue affiche `.dockerconfigjson` encodé en base64.

### Définir la politique de tirage d'image

Le champ `imagePullPolicy` contrôle quand le kubelet tire les images. Par défaut : `Always` pour l'étiquette `:latest`, `IfNotPresent` pour les étiquettes spécifiques. Pour le dépannage, vous pouvez définir `Always` pour forcer le tirage de la dernière version :

```yaml
spec:
  containers:
  - name: app
    image: myapp:1.0
    imagePullPolicy: Always
```

## Vérification et diagnostics

Après avoir appliqué les correctifs, vérifiez que les images sont tirées correctement et que les pods sont sains.

### Vérifier l'état des pods et les événements

```bash
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
```

Dans la section des événements, recherchez les messages `Pulled`, `Created`, `Started`. Les événements d'échec comme `Failed to pull image` ou `Back-off pulling image` indiquent des problèmes persistants. Exemple de bloc d'événements :

```
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  2m                 default-scheduler  Successfully assigned default/web-6d4b8c9f5-abcde to node-2
  Normal   Pulling    2m                 kubelet            Pulling image "nginx:1.21.6"
  Warning  Failed     2m                 kubelet            Failed to pull image "nginx:1.21.6": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/library/nginx:1.21.6": failed to resolve reference "docker.io/library/nginx:1.21.6": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
  Warning  Failed     2m                 kubelet            Error: ErrImagePull
  Normal   BackOff    2m (x3 over 2m)    kubelet            Back-off pulling image "nginx:1.21.6"
  Warning  Failed     2m (x3 over 2m)    kubelet            Error: ImagePullBackOff
```

### Inspecter les journaux

```bash
kubectl logs <pod-name> -n <namespace>
```

Pour le conteneur précédemment crashé :

```bash
kubectl logs <pod-name> -n <namespace> --previous
```

Si les journaux montrent des erreurs d'application non liées au tirage de l'image, l'image elle-même peut être incompatible avec le runtime de conteneurs (par exemple, mauvaise architecture). Exemple de journal d'une boucle de crash :

```
standard_init_linux.go:228: exec user process caused: exec format error
```

Cela indique souvent que l'image a été construite pour une architecture CPU différente (par exemple, image arm64 sur un nœud amd64).

### Vérifier le condensé de l'image

Les pods peuvent référencer les images par condensé pour l'immuabilité. Pour obtenir le condensé d'un pod en cours d'exécution :

```bash
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.containerStatuses[0].imageID}'
```

Sortie attendue comme `docker.io/library/nginx@sha256:abcdef1234567890...`.

### Tester manuellement le tirage de l'image

Si possible, tirez l'image sur le nœud ou depuis un conteneur de débogage :

```bash
kubectl run -it --rm debug --image=busybox --restart=Never -- sh
```

Dans le conteneur de débogage, essayez `nslookup <registry-host>` et `wget` pour vérifier la connectivité. (Remarque : busybox peut ne pas avoir `wget` ; utilisez `nc` ou `curl` dans une image appropriée.)

Alternativement, vérifiez les journaux du kubelet sur le nœud pour les erreurs de tirage :

```bash
journalctl -u kubelet -f | grep -i image
```

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

### Modes de défaillance courants

- **ImagePullBackOff** : Kubernetes tente à plusieurs reprises de tirer l'image mais échoue. Causes :
  - Nom ou étiquette d'image incorrect
  - Échec d'authentification au registre
  - Problèmes de connectivité réseau
  - Limitation de débit sur le registre
- **ErrImagePull** : Erreur immédiate de tirage, souvent due à des identifiants manquants ou une référence d'image invalide.
- **CrashLoopBackOff** : L'image a été tirée avec succès mais le conteneur se termine rapidement. Cela peut être dû à une erreur d'application, des dépendances manquantes ou une mauvaise architecture.
- **InvalidImageName** : Le champ image est mal formé (par exemple, contient des lettres majuscules ou des caractères invalides).

### Étapes de récupération

Pour chaque défaillance, suivez ces étapes :

#### ImagePullBackOff / ErrImagePull

- Vérifiez les événements du pod pour les erreurs détaillées :

```bash
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 Events
```

- Vérifiez le nom et l'étiquette de l'image par rapport au registre. Utilisez `docker pull` ou `crictl pull` depuis un nœud si possible.

- Vérifiez l'existence et l'exactitude du secret :

```bash
kubectl get secret <secret-name> -n <namespace> -o yaml
```

- Validez la connectivité réseau du nœud vers le registre.

- Corrigez le problème et déclenchez un nouveau déploiement :

```bash
kubectl rollout restart deployment/<deployment-name> -n <namespace>
```

#### CrashLoopBackOff

- Vérifiez les journaux :

```bash
kubectl logs <pod-name> -n <namespace> --previous
```

- Si l'erreur indique un fichier manquant ou une incompatibilité d'architecture, reconstruisez l'image avec un support multi-architectures correct ou utilisez une étiquette appropriée.
- Mettez à jour le déploiement avec l'image corrigée.

#### InvalidImageName

- Modifiez le déploiement et corrigez le champ image en utilisant le format approprié : `[registry/]image[:tag][@digest]`.
- Assurez-vous d'utiliser des minuscules et aucun espace.

### Stratégies de retour en arrière

Si un changement entraîne de nouvelles défaillances, revenez à une version connue comme bonne :

- Utilisez `kubectl rollout undo deployment/<deployment-name> -n <namespace>` pour revenir à la révision précédente.
- Vérifiez l'historique des déploiements :

```bash
kubectl rollout history deployment/<deployment-name> -n <namespace>
```

- Si le cluster est dans un mauvais état, envisagez de réduire la charge de travail défaillante et d'augmenter une charge stable.

## Pièges courants et comment les éviter

De nombreux problèmes d'images proviennent d'erreurs de configuration évitables ou de lacunes de processus. Voici les pièges les plus courants et comment les prévenir.

### 1. Utiliser l'étiquette `latest`

**Problème** : L'étiquette `latest` est mutable et peut être écrasée, entraînant des déploiements imprévisibles. Combinée à la politique par défaut `imagePullPolicy: Always`, le kubelet peut tirer une nouvelle version sans préavis.

**Évitement** : Utilisez toujours des étiquettes de version explicites ou des condensés en production. Par exemple, utilisez `nginx:1.21.6` au lieu de `nginx:latest`. Si vous devez utiliser `latest`, définissez `imagePullPolicy: IfNotPresent` pour éviter les tirages inattendus, mais cela n'est pas recommandé en production.

**Récupération** : Si un tirage `latest` a cassé votre déploiement, revenez à la révision précédente avec `kubectl rollout undo deployment/<deployment-name>` puis épinglez une étiquette spécifique.

### 2. Architectures incompatibles

**Problème** : Les conteneurs construits pour une architecture CPU (par exemple, arm64) échouent sur les nœuds d'une autre (par exemple, amd64) avec `exec format error` et `CrashLoopBackOff`.

**Évitement** : Construisez des images multi-architectures avec Docker Buildx ou des outils similaires, et utilisez des manifestes qui incluent toutes les architectures requises. Lors du déploiement, spécifiez la variante d'image correcte ou fiez-vous à la sélection automatique de la liste de manifestes.

**Récupération** : Vérifiez l'architecture du nœud avec `kubectl get nodes -o wide` et inspectez le manifeste de l'image pour les architectures prises en charge. Reconstruisez ou utilisez une étiquette d'image compatible.

### 3. Secrets de tirage d'image manquants ou incorrects

**Problème** : Les registres privés exigent des identifiants, mais le pod ou le compte de service ne dispose pas de `imagePullSecrets`, provoquant `ImagePullBackOff` avec des erreurs d'authentification.

**Évitement** : Stockez les identifiants du registre en tant que secret `docker-registry` et référencez-le soit dans la spécification du pod, soit, mieux, dans le compte de service par défaut de l'espace de noms. Utilisez `kubectl create secret docker-registry` comme indiqué précédemment.

**Récupération** : Créez le secret, corrigez le compte de service et redémarrez les pods affectés. Vérifiez avec `kubectl describe pod` que le tirage réussit.

### 4. Limites de débit du registre

**Problème** : Les registres publics comme Docker Hub imposent des limites de débit de tirage. Le dépassement provoque `ImagePullBackOff` avec des erreurs `toomanyrequests`.

**Évitement** : Utilisez un cache de transit (par exemple, Harbor, Artifactory) ou des comptes Docker Hub authentifiés avec des limites plus élevées. Surveillez les métriques de tirage du registre.

**Récupération** : Attendez la réinitialisation de la fenêtre de limite de débit ou passez à un cache/registre privé. Implémentez un backoff exponentiel dans le CI/CD pour réduire les tirages en rafale.

### 5. Politiques réseau ou pare-feu mal configurés

**Problème** : Le pare-feu ou les politiques réseau bloquent l'accès au registre, entraînant des délais d'attente et des échecs de tirage.

**Évitement** : Assurez-vous que le trafic sortant vers les hôtes du registre est autorisé. Testez la connectivité depuis les nœuds à l'aide de `telnet <registry-host> 443` ou `curl -v https://<registry-host>/v2/`.

**Récupération** : Mettez à jour les règles de pare-feu ou les politiques réseau, puis redémarrez les pods affectés.

### 6. Oublier de mettre à jour les références d'images partout

**Problème** : Un correctif est appliqué à un déploiement mais pas aux autres référençant la même image, entraînant un comportement incohérent.

**Évitement** : Utilisez une source unique de vérité pour les références d'images, comme un fichier de valeurs Helm ou une surcouche Kustomize, et mettez-la à jour globalement. Automatisez les mises à jour des étiquettes d'images avec le CI/CD.

**Récupération** : Recherchez toutes les charges de travail utilisant l'image problématique avec `kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].image | contains("myapp:old")) | .metadata.namespace + "/" + .metadata.name'` et mettez-les à jour.

## Liste de contrôle des opérations

Utilisez la liste de contrôle suivante pour vérifier systématiquement la santé des images et prévenir les problèmes récurrents. Attribuez un responsable unique pour chaque élément et une cadence de révision.

- [ ] Confirmer que les versions du cluster et des nœuds sont compatibles avec les images requises. Responsable : Ingénieur plateforme (par exemple, John Doe). Révision : mensuelle ou après les mises à niveau du cluster.
- [ ] S'assurer que toutes les références d'images sont correctement orthographiées et utilisent des étiquettes/condensés valides. Responsable : Développeur d'applications (par exemple, Jane Smith). Révision : à chaque déploiement.
- [ ] Vérifier que `imagePullSecrets` est présent et correctement configuré pour les registres privés. Responsable : Ingénieur DevOps (par exemple, Alex Johnson). Révision : trimestrielle ou lors de la rotation des identifiants du registre.
- [ ] Définir une `imagePullPolicy` appropriée à la stratégie de déploiement. Responsable : Développeur d'applications. Révision : à chaque déploiement.
- [ ] Après le déploiement, surveiller l'état des pods et les événements pour des tirages réussis. Responsable : Ingénieur en fiabilité des sites (par exemple, Emily Brown). Révision : surveillance continue avec alertes.
- [ ] Examiner régulièrement les limites de débit du registre et utiliser des caches de transit si nécessaire. Responsable : Ingénieur plateforme. Révision : mensuelle.
- [ ] Utiliser des étiquettes immuables (condensés) pour les charges de production afin d'éviter les changements inattendus. Responsable : Ingénieur DevOps. Révision : à chaque processus de publication.
- [ ] Implémenter des vérifications CI qui valident l'existence et l'architecture de l'image avant le déploiement. Responsable : Mainteneur du pipeline CI/CD (par exemple, Michael Lee). Révision : trimestrielle.

Le tableau ci-dessous résume les événements d'échec courants et leurs causes typiques :

| Événement d'échec | Cause typique | Commande de diagnostic clé |
|---|---|---|
| ImagePullBackOff | Authentification, mauvaise image, réseau | `kubectl describe pod` |
| ErrImagePull | Identifiants manquants, image invalide | `kubectl get events` |
| CrashLoopBackOff | Erreur d'application, incompatibilité d'architecture | `kubectl logs --previous` |
| InvalidImageName | Champ image mal formé | `kubectl describe pod` |

## Conclusion

Le dépannage des problèmes d'images Kubernetes nécessite une approche systématique : commencez par inventorier l'environnement, puis apportez des modifications de configuration sécuritaires, vérifiez par le biais de diagnostics et ayez des plans de récupération prêts. En suivant les commandes et les listes de contrôle de ce guide, les équipes peuvent réduire les temps d'arrêt et améliorer la fiabilité des déploiements. La clé est d'être méthodique : collectez les bonnes informations, appliquez les correctifs avec soin et vérifiez les résultats. N'oubliez pas que les problèmes d'images sont souvent le symptôme de lacunes de processus plus larges, comme un manque de gouvernance des images ou de validation CI/CD. S'attaquer à ces causes profondes préviendra les échecs futurs.