Introduction
Kubernetes masque de nombreux détails d'infrastructure, mais les défaillances du runtime de conteneurs peuvent arrêter complètement votre cluster. Le runtime de conteneurs est le logiciel qui exécute réellement vos conteneurs : il extrait les images, gère leur cycle de vie et assure l'isolation. Les runtimes les plus courants en production aujourd'hui sont containerd et CRI-O, Docker étant une option héritée. Lorsque le runtime se comporte mal, vous verrez des erreurs comme FailedCreatePodSandBox, ErrImagePull ou CreateContainerConfigError. Celles-ci apparaissent souvent sous forme d'événements de pod, mais la cause racine se situe dans la configuration ou l'environnement du runtime.
Ce guide présente les erreurs de runtime de conteneurs les plus fréquentes, comment les diagnostiquer et les corriger en toute sécurité. Vous apprendrez à vérifier votre configuration de runtime, à apporter des modifications ciblées et à récupérer après des tentatives échouées. Chaque correction comprend une commande concrète avec la sortie attendue, afin que vous puissiez l'appliquer à votre propre cluster en toute confiance.
Inventaire des versions et de l'environnement
Avant de modifier quoi que ce soit, rassemblez les versions exactes et la configuration du runtime. Cela évite les incompatibilités et facilite le retour arrière. Les commandes suivantes fonctionnent sur n'importe quel nœud Linux.
Vérifier le runtime actif
Kubernetes utilise l'interface CRI (Container Runtime Interface) pour communiquer avec le runtime. Déterminez quel runtime votre nœud utilise :
ps aux | grep -E 'containerd|crio|dockerd' | grep -v grep
Sortie attendue sur un nœud avec containerd :
root 1234 0.1 2.3 1234567 234567 ? Ssl Jan01 12:34 /usr/bin/containerd
Si vous voyez crio à la place, ajustez les commandes suivantes en conséquence. Pour Docker, notez qu'il utilise un shim (dockershim), qui est obsolète.
Confirmer la version du runtime
Chaque runtime fournit une commande de version. Pour containerd :
containerd --version
Sortie attendue :
containerd github.com/containerd/containerd v1.7.11
Pour CRI-O :
crictl version
La sortie attendue inclut les versions client et serveur. Si crictl n'est pas installé, installez-le depuis la page des releases Kubernetes ; c'est un outil de diagnostic essentiel.
Vérifier le socket CRI
Le kubelet doit se connecter au runtime via un socket Unix. Vérifiez le point de terminaison configuré :
ps aux | grep kubelet | grep -o '\(container-runtime-endpoint=[^ ]*\)'
Sortie attendue :
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
Si vous voyez unix:///var/run/crio/crio.sock, cela indique CRI-O. Notez le chemin pour plus tard.
Vérifier les fichiers de configuration du runtime
Les fichiers de configuration du runtime sont souvent la source d'erreurs. Pour containerd, la configuration par défaut est /etc/containerd/config.toml. Vérifiez les modifications récentes :
stat /etc/containerd/config.toml
Regardez l'heure de modification pour voir si elle a changé avant l'incident. Pour CRI-O, le fichier de configuration principal est /etc/crio/crio.conf.
Vérifier l'état du nœud
Utilisez kubectl pour voir les conditions du nœud, qui incluent la santé du runtime :
kubectl describe node <nom-du-nœud> | grep -A5 Conditions
Recherchez ContainerRuntimeIsReady ou KubeletReady. Si c'est False ou Unknown, le runtime est défaillant.
Vérifier l'état du runtime avec systemctl
Si le service du runtime ne fonctionne pas, rien d'autre ne compte. Vérifiez avec :
systemctl status containerd
Sortie attendue en bonne santé :
● containerd.service - containerd container runtime
Loaded: loaded (/usr/lib/systemd/system/containerd.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2025-04-18 10:15:22 UTC; 1 day ago
Si c'est failed ou inactive, consultez les journaux avec journalctl -u containerd -n 50 --no-pager.
Documenter votre base de référence
| Composant | Exemple de commande | Sortie saine typique |
|---|
| Processus du runtime | ps aux | grep containerd | Processus listé avec chemin |
| Version du runtime | containerd --version | Chaîne de version, par exemple v1.7.11 |
| Socket CRI | ls -l /run/containerd/containerd.sock | Le fichier socket existe |
| Préparation du nœud | kubectl get node | Statut Ready |
Cet inventaire vous donne une base de référence. Si une correction échoue, vous pouvez comparer avec ces valeurs.
Chemin de configuration sûr
La configuration du runtime de conteneurs est sensible. Une petite erreur peut empêcher tous les pods de démarrer. Suivez une approche ciblée : modifiez un paramètre à la fois, testez dans un environnement hors production et ayez un plan de retour arrière.
Erreurs courantes du runtime et leurs causes
Avant d'apporter des modifications, comprenez les catégories d'erreurs :
| Message d'erreur | Cause probable | Composant du runtime |
|---|---|---|
FailedCreatePodSandBox | Plugin CNI manquant ou mal configuré | Plugin réseau |
ErrImagePull / ImagePullBackOff | Problème d'authentification au registre ou de réseau | Extraction d'image |
CreateContainerConfigError | Spécification de conteneur invalide, par exemple ConfigMap manquante | Kubelet / runtime |
runc run failed: unable to start container process | Problème de seccomp, AppArmor ou de capacités | Runtime OCI (runc) |
cgroups: cgroup mountpoint does not exist | Discordance du pilote cgroup systemd | Configuration cgroup |
Nous traiterons chacune avec une correction concrète.
Correction 1 : Configurer le bon pilote cgroup
Un problème fréquent est une discordance entre le pilote cgroup utilisé par le runtime et le kubelet. Sur les systèmes basés sur systemd, les deux doivent utiliser systemd. Vérifiez le pilote du kubelet :
ps aux | grep kubelet | grep -o 'cgroup-driver=[^ ]*'
Si cela renvoie --cgroup-driver=cgroupfs mais que votre runtime utilise systemd, vous verrez des erreurs comme :
failed to create container: cgroup manager: failed to create cgroup: cgroups: cgroup mountpoint does not exist
Pour containerd, modifiez /etc/containerd/config.toml :
sudo vi /etc/containerd/config.toml
Assurez-vous que la section suivante est présente :
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
Puis redémarrez containerd :
sudo systemctl restart containerd
Redémarrez kubelet :
sudo systemctl restart kubelet
Vérifiez avec :
sudo journalctl -u kubelet -n 20 | grep -i cgroup
Vous ne devriez voir aucune erreur cgroup. Sur CRI-O, définissez cgroup_manager = "systemd" dans /etc/crio/crio.conf sous [crio.runtime].
Correction 2 : Configurer les secrets d'extraction d'image
De nombreuses erreurs ErrImagePull sont dues à des identifiants manquants pour les registres privés. Créez un secret :
kubectl create secret docker-registry my-registry-secret \
--docker-server=myregistry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
[email protected]
Puis référencez-le dans la spécification de votre pod :
spec:
imagePullSecrets:
- name: my-registry-secret
containers:
- name: app
image: myregistry.example.com/app: v1
Appliquez et vérifiez :
kubectl apply -f pod.yaml
kubectl get pod <nom-du-pod> -o wide
Si le pod est Running, l'extraction a réussi. Sinon, vérifiez les événements : kubectl describe pod <nom-du-pod> et recherchez Failed to pull image avec une raison comme 401 Unauthorized ou dial tcp: lookup myregistry.example.com: no such host.
Correction 3 : Configurer le plugin réseau CNI
Un plugin réseau cassé provoque des erreurs FailedCreatePodSandBox. Vérifiez que le répertoire de configuration CNI existe et contient une configuration valide :
ls /etc/cni/net.d/
cat /etc/cni/net.d/*.conf
Une configuration CNI typique pour Calico ou Flannel inclut un champ type. Si le fichier est manquant, installez un plugin CNI. Par exemple, pour installer Calico :
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
Après l'installation, vérifiez que les pods CNI fonctionnent :
kubectl get pods -n kube-system | grep calico
Puis testez la création d'un pod :
kubectl run test-pod --image=nginx --restart=Never
kubectl get pod test-pod
S'il passe à Running, le réseau est corrigé.
Correction 4 : Configurer RuntimeClass (optionnel)
Pour les charges de travail spécialisées, vous pouvez définir une RuntimeClass pour sélectionner un runtime différent. Créez un objet RuntimeClass :
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
Appliquez-le et référencez-le dans un pod :
kubectl apply -f runtimeclass.yaml
Dans la spécification du pod :
spec:
runtimeClassName: gvisor
containers:
- name: test
image: nginx
Si le gestionnaire n'est pas installé, vous obtiendrez une erreur comme Failed to create pod sandbox: unknown runtime handler. Assurez-vous que le gestionnaire de runtime est configuré sur chaque nœud.
Vérification et diagnostics
Après avoir appliqué une correction, vérifiez que le runtime est sain et que les pods peuvent s'exécuter. Utilisez ces commandes pour confirmer.
Vérifier le service du runtime
Vérifiez que le service du runtime est actif et ne redémarre pas :
systemctl status containerd --no-pager -l
Recherchez Active: active (running) et aucune erreur récente dans les journaux :
journalctl -u containerd -n 50 --no-pager
Vérifier la connectivité CRI
Utilisez crictl pour parler directement au runtime via le CRI. Vérifiez la version du runtime :
crictl version
La sortie attendue montre les versions client et serveur. Ensuite, listez les pods actuels du point de vue du runtime :
crictl pods
Vous devriez voir une liste de pods. Si cela renvoie une erreur comme connection refused, le chemin du socket peut être incorrect. Vérifiez la configuration du kubelet et ajustez le point de terminaison crictl :
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
crictl pods
Vérifier le cycle de vie des pods
Créez un pod de test simple et observez son état :
kubectl run runtime-test --image=nginx --restart=Never
kubectl get pod runtime-test -w
Attendez qu'il soit Running (ou Completed si vous remplacez la commande). S'il reste en Pending ou ContainerCreating, vérifiez les événements :
kubectl describe pod runtime-test
Recherchez des événements comme FailedCreatePodSandBox ou Failed to pull image. Une fois vérifié, supprimez le pod de test :
kubectl delete pod runtime-test
Vérifier les conditions du nœud
Après une correction, attendez un moment et vérifiez à nouveau les conditions du nœud :
kubectl describe node <nom-du-nœud> | grep -A5 Conditions
ContainerRuntimeIsReady doit être True, et le nœud doit être Ready.
Résumé des commandes de diagnostic
| Vérification | Commande | Sortie saine attendue |
|---|---|---|
| Statut du service du runtime | systemctl status containerd | active (running) |
| Connectivité CRI | crictl version | Version du serveur renvoyée |
| Test de création de pod | kubectl run ... --image=nginx | Le pod devient Running |
| Condition du nœud | kubectl describe node | RuntimeReady=True |
Modes de défaillance et récupération
Même avec des changements prudents, les choses peuvent mal tourner. Voici des scénarios de défaillance courants après un changement de configuration du runtime et comment récupérer.
Défaillance : le runtime ne démarre pas après un changement de configuration
Si containerd ne démarre pas après avoir modifié config.toml, vérifiez les journaux pour des erreurs de syntaxe :
sudo journalctl -u containerd -n 50 --no-pager
Recherchez des lignes comme failed to load config: near line 10: unexpected token. Faites un retour arrière en restaurant le fichier de configuration précédent :
sudo cp /etc/containerd/config.toml.backup /etc/containerd/config.toml
sudo systemctl restart containerd
Puis redémarrez kubelet :
sudo systemctl restart kubelet
Défaillance : le kubelet ne peut pas se connecter au runtime
Si le chemin du socket CRI a changé ou si le runtime est arrêté, le kubelet renverra une erreur. Vérifiez les journaux du kubelet :
sudo journalctl -u kubelet -n 50 --no-pager
Recherchez failed to connect to containerd ou dial unix /run/containerd/containerd.sock: connect: no such file or directory. Vérifiez que le socket existe :
ls -l /run/containerd/containerd.sock
S'il est manquant, assurez-vous que containerd fonctionne. Si le chemin du socket est incorrect dans la configuration du kubelet, mettez à jour /var/lib/kubelet/config.yaml ou le drop-in du kubelet. Puis redémarrez le kubelet.
Défaillance : pods bloqués en état Terminating
Si un pod ne peut pas être supprimé parce que le runtime ne répond pas, forcez la suppression du pod :
kubectl delete pod <nom-du-pod> --force --grace-period=0
Si cela ne fonctionne pas, redémarrez le runtime :
sudo systemctl restart containerd
Ensuite, nettoyez les conteneurs orphelins avec crictl rm :
crictl ps -a | grep <nom-du-pod>
crictl rm <id-du-conteneur>
Planification du retour arrière
Faites toujours une sauvegarde des configurations du runtime avant de les modifier :
sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.backup
Pour CRI-O :
sudo cp /etc/crio/crio.conf /etc/crio/crio.conf.backup
Notez également les modifications exactes apportées, afin de pouvoir les annuler manuellement si nécessaire.
Liste de contrôle des opérations
Utilisez cette liste de contrôle pour auditer régulièrement votre runtime de conteneurs et accélérer le dépannage.
Vérifications quotidiennes ou hebdomadaires
- Vérifiez que le service du runtime est actif :
systemctl is-active containerddoit renvoyeractive. - Vérifiez la préparation des nœuds :
kubectl get nodesdoit montrer tous les nœudsReady. - Surveillez les journaux du runtime pour des erreurs répétées :
journalctl -u containerd --since "24 hours ago" | grep -i error. - Vérifiez l'espace disque sur
/var/lib/containerd(stockage des images) et/var/lib/kubelet(stockage des pods) avecdf -h. - Assurez-vous que les pods CNI critiques fonctionnent :
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave|cilium'.
Avant d'apporter des modifications de configuration
- Sauvegardez les fichiers de configuration actuels du runtime.
- Enregistrez la version actuelle du runtime et du kubelet.
- Testez les modifications dans un environnement de préproduction d'abord.
- Planifiez les étapes de retour arrière.
- Planifiez une fenêtre de maintenance si nécessaire.
Après avoir apporté des modifications de configuration
- Redémarrez le service du runtime et vérifiez son état.
- Redémarrez kubelet et vérifiez son état.
- Vérifiez la connectivité CRI avec
crictl version. - Exécutez un pod de test pour confirmer la fonctionnalité.
- Vérifiez les conditions du nœud pour la préparation du runtime.
- Surveillez les journaux pour de nouvelles erreurs pendant au moins 10 minutes.
Audit mensuel
- Examinez la configuration du runtime par rapport aux meilleures pratiques (par exemple, pilote cgroup, paramètres CNI).
- Recherchez des mises à jour du runtime et appliquez-les de manière contrôlée.
- Testez la création, la suppression et l'exécution de pods.
- Validez l'extraction d'images depuis tous les registres utilisés.
Pièges courants et idées fausses
Même les opérateurs expérimentés tombent dans ces pièges récurrents. Les comprendre à l'avance peut économiser des heures de débogage.
Piège 1 : Mélanger les pilotes cgroup
Pourquoi cela arrive : Vous installez un runtime qui utilise cgroupfs par défaut sur un hôte systemd, ou vous copiez une configuration Kubernetes d'un ancien déploiement sans mettre à jour le pilote.
Comment éviter : Définissez toujours à la fois kubelet et runtime sur systemd sur les systèmes d'exploitation avec systemd. Ajoutez une vérification avant le déploiement :
# Vérifier le pilote du runtime
containerd config dump | grep -i systemd_cgroup
# Vérifier le pilote du kubelet
ps aux | grep kubelet | grep -o 'cgroup-driver=[^ ]*'
S'ils diffèrent, corrigez avant de déployer des charges de travail.
Récupération : Appliquez la correction 1, puis redémarrez les services. Vérifiez en créant un pod de test ; s'il échoue toujours, inspectez journalctl -u kubelet pour des erreurs cgroup.
Piège 2 : Modifier la configuration du runtime sans sauvegardes
Pourquoi cela arrive : Vous avez besoin d'une correction rapide pendant un incident et sautez l'étape de sauvegarde.
Comment éviter : Intégrez les sauvegardes dans votre processus de changement. Utilisez une copie horodatée :
sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.$(date +%Y%m%d%H%M%S).bak
Récupération : Si vous n'avez pas sauvegardé, vérifiez le gestionnaire de paquets pour la configuration d'origine : rpm -V containerd ou dpkg -S containerd. Pour un système en cours d'exécution, vous pouvez extraire la configuration actuelle avec containerd config dump et l'enregistrer.
Piège 3 : Supposer que CNI est toujours préinstallé
Pourquoi cela arrive : Les services Kubernetes gérés installent souvent CNI automatiquement, mais les clusters auto-gérés nécessitent une configuration manuelle.
Comment éviter : Après l'amorçage du cluster, vérifiez immédiatement que les pods CNI fonctionnent et testez avec un pod exemple avant de déployer des charges de travail de production.
Récupération : Installez un plugin CNI comme décrit dans la correction 3. Si les pods sont bloqués en ContainerCreating, vérifiez les événements pour des erreurs de sandbox.
Piège 4 : Ignorer la rotation des journaux du runtime
Pourquoi cela arrive : Le runtime écrit les journaux sur le disque sans rotation, remplissant le système de fichiers au fil du temps.
Comment éviter : Configurez la rotation des journaux dans la configuration du runtime. Pour containerd, définissez :
[plugins."io.containerd.grpc.v1.cri".containerd]
max_container_log_line_size = 16384
Et assurez-vous que les limites de journald de systemd sont appropriées. Surveillez régulièrement l'utilisation du disque.
Récupération : Si le disque est plein, élaguez les images inutilisées (crictl rmi --prune) et supprimez les anciens journaux. Ensuite, configurez la rotation pour éviter la récurrence.
Piège 5 : Exécuter des conteneurs en tant que root par défaut
Pourquoi cela arrive : De nombreuses images de conteneurs utilisent par défaut l'utilisateur root, augmentant le rayon d'impact d'une évasion.
Comment éviter : Appliquez la non-root avec des politiques de sécurité des pods ou des contrôleurs d'admission. Dans la spécification de votre pod :
securityContext:
runAsNonRoot: true
runAsUser: 1000
Récupération : Si un conteneur s'exécute en tant que root, mettez à jour l'image ou le contexte de sécurité. Vous pouvez également définir une RuntimeClass par défaut avec runAsNonRoot appliqué.
Conclusion
Les erreurs de runtime de conteneurs peuvent être intimidantes, mais elles sont généralement causées par quelques mauvaises configurations courantes. En vérifiant méthodiquement les pilotes cgroup, les paramètres d'extraction d'images, le réseau CNI et la santé du runtime, vous pouvez résoudre la plupart des problèmes rapidement. Travaillez toujours avec un chemin de configuration sûr : apportez une modification à la fois, vérifiez avec des commandes concrètes et ayez un plan de retour arrière. La liste de contrôle fournie vous aidera à maintenir un runtime sain et à minimiser les temps d'arrêt. Avec ces exemples pratiques et ces commandes de diagnostic, vous pouvez dépanner et corriger en toute confiance les erreurs de runtime de conteneurs Kubernetes dans votre propre environnement.