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é :
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 :
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 :
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 :
kubectl edit deployment <deployment-name> -n <namespace>
Ou appliquez un correctif :
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 :
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 :
kubectl create secret docker-registry regcred \
--docker-server=myregistry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
[email protected] \
-n default
Ajoutez ensuite imagePullSecrets à la spécification du pod ou au compte de service. Corrigez le compte de service :
kubectl patch serviceaccount default -n default -p '{"imagePullSecrets": [{"name": "regcred"}]}'
Vérifiez que le secret existe :
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 :
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
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
kubectl logs <pod-name> -n <namespace>
Pour le conteneur précédemment crashé :
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 :
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 :
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 :
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 :
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 pulloucrictl pulldepuis un nœud si possible.
- Vérifiez l'existence et l'exactitude du secret :
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 :
kubectl rollout restart deployment/<deployment-name> -n <namespace>
CrashLoopBackOff
- Vérifiez les journaux :
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 :
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
imagePullSecretsest 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
imagePullPolicyapproprié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.