Note de traduction.: Cet article fait partie des ressources publiées en accès libre du projet , formant les administrateurs individuels et ceux travaillant avec Kubernetes. Dans celui-ci, Daniele Polencic, chef de projet, partage un guide visuel sur les étapes à suivre en cas de problèmes généraux avec les applications déployées dans un cluster K8s.

TL;DR : voici un schéma qui vous aidera à déboguer le déploiement dans Kubernetes :
Diagramme pour trouver et corriger des erreurs dans un cluster. En version originale (en anglais), il est disponible chez et .
Lors du déploiement d'une application dans Kubernetes, il est généralement nécessaire de définir trois composants :
- Déploiement — c'est une sorte de recette pour créer des copies de l'application appelées pods ;
- Service — un équilibreur de charge interne qui distribue le trafic entre les pods ;
- Ingress — une description de la façon dont le trafic passera du monde externe au Service.
Voici un résumé graphique succinct :
1) Dans Kubernetes, les applications reçoivent le trafic du monde externe via deux couches d'équilibreurs de charges : interne et externe.

2) L'équilibreur de charge interne s'appelle Service, l'externe – Ingress.

3) Le déploiement crée des pods et les surveille (ils ne sont pas créés manuellement).

Supposons que vous souhaitiez déployer une simple application de type Hello World. La configuration YAML pour cela ressemblerait à ceci :
apiVersion: apps/v1
kind: Deployment # <<<
metadata:
name: my-deployment
labels:
track: canary
spec:
selector:
matchLabels:
any-name: my-app
template:
metadata:
labels:
any-name: my-app
spec:
containers:
- name: cont1
image: learnk8s/app:1.0.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service # <<<
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080
selector:
name: app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress # <<<
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- backend:
serviceName: app
servicePort: 80
path: /La définition est assez longue, et il est facile de se perdre dans la façon dont les composants sont liés les uns aux autres.
Par exemple :
- Quand devez-vous utiliser le port 80, et quand le port 8080 ?
- Devez-vous créer un nouveau port pour chaque service afin qu'ils ne soient pas en conflit ?
- Les noms des labels ont-ils de l'importance ? Devraient-ils être identiques partout ?
Avant de nous concentrer sur le débogage, rappelons-nous comment les trois composants sont liés les uns aux autres. Commençons par le Déploiement et le Service.
Lien entre le Déploiement et le Service
Vous serez surpris, mais les Déploiements et les Services ne sont pas liés. Au lieu de cela, le Service pointe directement vers les Pods en contournant le Déploiement.
Ainsi, nous nous intéressons à la façon dont les Pods et les Services sont interconnectés. Il y a trois choses à garder à l'esprit :
- Le sélecteur (
selector) d'un Service doit correspondre à au moins une étiquette d'un Pod. -
targetPortdoit correspondre àcontainerPortdu conteneur à l'intérieur du Pod. -
portLe port d'un Service peut être quelconque. Différents services peuvent utiliser le même port car ils ont des adresses IP différentes.
Le schéma suivant représente tout ce qui précède sous forme graphique :
1) Supposons qu'un service dirige le trafic vers un pod :

2) Lors de la création d'un pod, vous devez spécifier containerPort pour chaque conteneur dans les pods :

3) Lors de la création d'un service, il est nécessaire de spécifier port et targetPort. Mais par lequel se fait la connexion au conteneur ?

4) Par targetPort. Il doit correspondre à containerPort.

5) Supposons que le port 3000 soit ouvert dans le conteneur. Alors la valeur targetPort doit être la même.

Dans le fichier YAML, les étiquettes et ports / targetPort doivent correspondre :
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
labels:
track: canary
spec:
selector:
matchLabels:
any-name: my-app
template:
metadata:
labels: # <<<
any-name: my-app # <<<
spec:
containers:
- name: cont1
image: learnk8s/app:1.0.0
ports:
- containerPort: 8080 # <<<
---
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- port: 80
targetPort: 8080 # <<<
selector: # <<<
any-name: my-app # <<< Qu'en est-il de l'étiquette track: canary dans le haut de la section Deployment ? Doit-elle correspondre ?
Cette étiquette se rapporte au déploiement et n'est pas utilisée par le service pour le routage du trafic. En d'autres termes, elle peut être supprimée ou avoir une autre valeur.
Et qu'en est-il du sélecteur ? matchLabels?
Il doit toujours correspondre aux étiquettes du Pod, car il est utilisé par le Deployment pour suivre les pods.
Supposons que vous ayez effectué les corrections adéquates. Comment les vérifier ?
Pour vérifier les étiquettes des pods, vous pouvez utiliser la commande suivante :
kubectl get pods --show-labelsOu, si les pods appartiennent à plusieurs applications :
kubectl get pods --selector any-name=my-app --show-labels Où any-name=my-app est une étiquette any-name: my-app.
Des difficultés demeurent ?
Vous pouvez vous connecter au pod ! Pour cela, utilisez la commande port-forward dans kubectl. Elle permet de se connecter au service et de vérifier la connexion.
kubectl port-forward service/<nom du service> 3000:80Ici :
-
service/<nom du service>est le nom du service ; dans notre cas, c'estmy-service; - 3000 est le port à ouvrir sur l'ordinateur ;
- 80 est le port spécifié dans le champ
portpour le service.
Si la connexion a été établie, cela signifie que les configurations sont correctes.
Si la connexion n'a pas pu être établie, cela signifie qu'il y a un problème avec les labels ou que les ports ne correspondent pas.
La communication entre le Service et l'Ingress
La prochaine étape pour garantir l'accès à l'application consiste à configurer l'Ingress. L'Ingress doit savoir comment trouver le service, puis localiser les pods et diriger le trafic vers eux. L'Ingress trouve le service requis par son nom et le port ouvert.
Dans la description de l'Ingress et du Service, deux paramètres doivent correspondre :
-
servicePortdans l'Ingress doit correspondre au paramètreportdans le Service ; -
serviceNamedans l'Ingress doit correspondre au champnomdans le Service.
Le schéma suivant résume la connexion des ports :
1) Comme vous le savez déjà, le Service écoute un certain port:

2) L'Ingress a un paramètre appelé servicePort:

3) Ce paramètre (servicePort) doit toujours correspondre à port dans la définition du Service :

4) Si le port 80 est spécifié dans le Service, il est nécessaire que servicePort soit également égal à 80 :

Dans la pratique, il est important de prêter attention aux lignes suivantes :
apiVersion: v1
kind: Service
metadata:
name: my-service # <<<
spec:
ports:
- port: 80 # <<<
targetPort: 8080
selector:
any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- backend:
serviceName: my-service # <<<
servicePort: 80 # <<<
path: /Comment vérifier si l'Ingress fonctionne ?
Vous pouvez utiliser la méthode avec kubectl port-forward, mais au lieu de connecter le service, vous devez vous connecter à contrôleur Ingress.
Tout d'abord, vous devez connaître le nom du pod avec le contrôleur Ingress :
kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS
kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
kube-system etcd-minikube 1/1 Running
kube-system kube-apiserver-minikube 1/1 Running
kube-system kube-controller-manager-minikube 1/1 Running
kube-system kube-proxy-zvf2h 1/1 Running
kube-system kube-scheduler-minikube 1/1 Running
kube-system nginx-ingress-controller-6fc5bcc 1/1 Running Trouvez le pod de l'Ingress (il peut appartenir à un autre espace de noms) et exécutez la commande describe, pour connaître les numéros de ports :
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPEnfin, connectez-vous au pod :
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemMaintenant, chaque fois que vous enverrez une requête au port 3000 sur votre ordinateur, elle sera redirigée vers le port 80 du pod avec le contrôleur Ingress. En accédant à , vous devriez voir la page générée par l'application.
Résumé des ports
Rappelons encore une fois quels ports et labels doivent correspondre :
- Le sélecteur dans la définition du Service doit correspondre au label du pod ;
-
targetPortdans la définition du Service doit correspondre àcontainerPortdu conteneur à l'intérieur du pod ; -
portLa définition du Service peut être quelconque. Différents services peuvent utiliser le même port, car ils ont des adresses IP différentes. -
servicePortL'Ingress doit correspondre àportla définition du Service. - Le nom du service doit correspondre au champ
serviceNamedans l'Ingress.
Hélas, il ne suffit pas de savoir comment structurer correctement la configuration YAML.
Que se passe-t-il lorsque quelque chose ne fonctionne pas ?
Il est possible que le pod ne démarre pas ou qu'il plante.
3 étapes pour diagnostiquer les problèmes d'applications dans Kubernetes
Avant de commencer le débogage du déploiement, il est essentiel d'avoir une bonne compréhension du fonctionnement de Kubernetes.
Puisque chaque application déployée dans K8s a trois composants, le débogage doit se faire dans un certain ordre, en commençant par le bas.
- D'abord, il faut s'assurer que les pods fonctionnent, ensuite...
- Vérifier si le service délivre du trafic aux pods, puis...
- Vérifier si l'Ingress est correctement configuré.
Représentation visuelle :
1) Commencez la recherche de problèmes par le bas. D'abord, vérifiez que les pods sont dans l'état Prêt et Running:

2) Si les pods sont prêts (Prêt), il faut déterminer si le service répartit le trafic entre les pods :

3) Enfin, il est nécessaire d'analyser la relation entre le service et l'Ingress :

1. Diagnostic des pods
Dans la plupart des cas, le problème est lié au pod. Assurez-vous que les pods apparaissent comme Prêt et Running. Vous pouvez vérifier cela en utilisant la commande :
kubectl get pods
NAME READY STATUS RESTARTS AGE
app1 0/1 ImagePullBackOff 0 47h
app2 0/1 Error 0 47h
app3-76f9fcd46b-xbv4k 1/1 Running 1 47h Dans la sortie de la commande ci-dessus, le dernier pod apparaît comme Running et Prêt, mais ce n'est pas le cas pour les deux autres.
Comment savoir ce qui ne va pas ?
Il existe quatre commandes utiles pour diagnostiquer les pods :
-
kubectl logspermet d'extraire les journaux des conteneurs dans le pod ; -
kubectl describe podpermet de visualiser la liste des événements associés au pod ; -
kubectl get podpermet d'obtenir la configuration YAML du pod stockée dans Kubernetes ; -
kubectl exec -ti bashpermet de lancer un terminal interactif dans l'un des conteneurs du pod.
Laquelle choisir ?
Le fait est qu'il n'y a pas de commande universelle. Il convient d'utiliser une combinaison de celles-ci.
Problèmes typiques des pods
Il existe deux principaux types d'erreurs concernant les pods : les erreurs au moment du démarrage (startup) et les erreurs pendant l'exécution (runtime).
Erreurs de démarrage :
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
NomDImageInvalide
Erreurs d'exécution :
-
CrashLoopBackOff -
ErreurExécutionConteneur -
ErreurTuerConteneur -
ErreurVérifierNonRoot -
ErreurExécutionConteneurInit -
ErreurCréerPodSandbox -
ErreurConfigPodSandbox -
ErreurTuerPodSandbox -
Certaines erreurs se produisent plus fréquemment que d'autres. Voici quelques-unes des erreurs les plus courantes et comment les résoudre. -
ImagePullBackOff
Cette erreur apparaît lorsque Kubernetes ne peut pas obtenir l'image pour l'un des conteneurs du pod. Voici trois des raisons les plus courantes à cela :
Nom d'image incorrect — par exemple, vous avez fait une erreur dedans ou l'image n'existe pas ;
Tag d'image inexistant spécifié ;
- L'image est stockée dans un registre privé, et Kubernetes n'a pas les autorisations pour y accéder.
- Les deux premières raisons sont faciles à résoudre — il suffit de corriger le nom et le tag de l'image. Pour le dernier, il faut fournir les informations d'identification du registre privé dans Secret et ajouter les références dans les pods. Dans la documentation Kubernetes
- il existe un exemple
de comment cela peut être fait. , si le conteneur ne peut pas démarrer. Cela se produit généralement lorsqu'il y a :
CrashLoopBackOff
une erreur dans l'application qui empêche son démarrage ; CrashLoopBackOffconfiguration incorrecte
- Le test Liveness a échoué trop de fois.
- Conteneur ;
- kubectl logs --previous
Celle-ci affiche les messages d'erreur de la réincarnation précédente du conteneur.
Cette erreur se produit lorsque le conteneur ne parvient pas à démarrer. Elle correspond à un moment avant le lancement de l'application. Sa cause est généralement une configuration incorrecte, par exemple :essayer de monter un volume inexistant, tel qu'un ConfigMap ou des Secrets ;
ErreurExécutionConteneur
essayer de monter un volume en lecture seule comme en lecture-écriture.
- Pour analyser ce type d'erreur, la commande suivante est utile
- kubectl describe pod
Les pods en état d'attente Après la création, le pod reste en état.
Pourquoi cela se produit-il ?
Voici quelques raisons possibles (je pars du principe que le planificateur fonctionne normalement) : Pending.
Il n'y a pas assez de ressources dans le cluster, comme de la puissance de calcul et de la mémoire, pour exécuter le pod.
Un objet de l'espace de noms approprié est installé
- ResourceQuota
- Un objet est installé dans l'espace de noms correspondant
ResourceQuotaet la création du pod entraînera un dépassement de la quota de l’espace de noms. - Le Pod est lié à Pending
PersistentVolumeClaim.
Dans ce cas, il est recommandé d'utiliser la commande kubectl describe et de vérifier la section Événements:
kubectl describe pod En cas d'erreurs liées à ResourceQuotas, il est conseillé de consulter les journaux du cluster à l'aide de la commande
kubectl get events --sort-by=.metadata.creationTimestampLes Pods ne sont pas dans l'état Ready
Si le pod apparaît comme Running, mais n'est pas dans l'état Prêt, cela signifie que la vérification de sa disponibilité (readiness probe) échoue.
Lorsque cela se produit, le pod ne se connecte pas au service, et le trafic ne lui parvient pas. L'échec du test de disponibilité est causé par des problèmes dans l'application. Dans ce cas, il est nécessaire d'analyser la section Événements dans la sortie de la commande kubectl describe.
2. Diagnostic des services
Si les pods apparaissent comme Running et Prêt, mais qu'il n'y a toujours pas de réponse de l'application, il faut vérifier la configuration du service.
Les services gèrent le routage du trafic vers les pods en fonction de leurs labels. Ainsi, la première chose à faire est de vérifier combien de pods fonctionnent avec le service. Pour cela, vous pouvez vérifier les endpoints dans le service :
kubectl describe service | grep Endpoints Un endpoint est une paire de valeurs de type <IP-адрес:порт>, et dans la sortie, il devrait y avoir au moins une telle paire (c'est-à-dire qu'au moins un pod fonctionne avec le service).
Si la section Endpoints est vide, deux scénarios sont possibles :
- il n'y a aucun pod avec le bon label (indice : vérifiez si le namespace est correctement sélectionné);
- il y a une erreur dans les labels du service dans le sélecteur.
Si vous voyez la liste des endpoints, mais que vous ne pouvez toujours pas accéder à l'application, il est probable que la cause soit une erreur dans targetPort la description du service.
Comment vérifier la fonctionnalité du service ?
Quel que soit le type de service, vous pouvez utiliser la commande kubectl port-forward pour vous connecter :
kubectl port-forward service/ 3000:80Ici :
-
<service-name>— le nom du service; - 3000 — le port que vous ouvrez sur votre ordinateur;
- 80 — le port du côté du service.
3. Diagnostic de l'Ingress
Si vous avez lu jusqu'ici, alors :
- les pods apparaissent comme
RunningetPrêt; - le service répartit avec succès le trafic entre les pods.
Cependant, vous ne pouvez toujours pas accéder à l'application.
Cela signifie qu'il est probable que le contrôleur Ingress soit mal configuré. Étant donné que le contrôleur Ingress est un composant tiers dans le cluster, divers méthodes de débogage existent en fonction de son type.
Mais avant de recourir à des outils spécialisés pour configurer l'Ingress, vous pouvez faire quelque chose de très simple. L'Ingress utilise serviceName et servicePort pour se connecter au service. Il est nécessaire de vérifier s'ils sont correctement configurés. Vous pouvez le faire avec la commande :
kubectl describe ingress Si la colonne Backend est vide, il y a une forte probabilité d'une erreur de configuration. Si les backends sont présents mais que l'accès à l'application est toujours impossible, le problème pourrait être lié à :
- les paramètres d'accessibilité de l'Ingress depuis Internet public ;
- les paramètres d'accessibilité du cluster depuis Internet public.
Vous pouvez identifier les problèmes d'infrastructure en vous connectant directement au pod de l'Ingress. Pour cela, commencez par trouver le pod du contrôleur Ingress (il peut se trouver dans un autre espace de noms) :
kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS
kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
kube-system etcd-minikube 1/1 Running
kube-system kube-apiserver-minikube 1/1 Running
kube-system kube-controller-manager-minikube 1/1 Running
kube-system kube-proxy-zvf2h 1/1 Running
kube-system kube-scheduler-minikube 1/1 Running
kube-system nginx-ingress-controller-6fc5bcc 1/1 Running Utilisez la commande describe, pour définir le port :
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep PortsEnfin, connectez-vous au pod :
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemMaintenant, toutes les requêtes sur le port 3000 de l'ordinateur seront redirigées vers le port 80 du pod.
Est-ce qu'il fonctionne maintenant ?
- Si oui, alors le problème vient de l'infrastructure. Il faut déterminer comment le trafic est routé vers le cluster.
- Si non, alors le problème vient du contrôleur Ingress.
Si vous n'arrivez pas à faire fonctionner le contrôleur Ingress, vous devrez le déboguer.
Il existe de nombreuses variantes de contrôleurs Ingress. Les plus populaires sont Nginx, HAProxy, Traefik, etc. (pour en savoir plus sur les solutions existantes, voir notre critique — n.d.t.) Il est conseillé de consulter le guide de dépannage dans la documentation du contrôleur concerné. Étant donné que est le contrôleur Ingress le plus populaire, nous avons inclus dans l'article quelques conseils pour résoudre les problèmes qui y sont liés.
Débogage du contrôleur Ingress Nginx
Le projet Ingress-nginx a un . La commande kubectl ingress-nginx peut être utilisée pour :
- analyser les logs, les backends, les certificats, etc. ;
- se connecter à l'Ingress ;
- examiner la configuration actuelle.
Les trois commandes suivantes vous aideront :
-
kubectl ingress-nginx lint— vérifienginx.conf; -
kubectl ingress-nginx backend— explore le backend (similaire àkubectl describe ingress); -
kubectl ingress-nginx logs— vérifie les logs.
Veuillez noter : dans certains cas, il peut être nécessaire d'indiquer le bon espace de noms pour le contrôleur Ingress avec l'option --namespace.
Résumé
Le diagnostic dans Kubernetes peut s'avérer une tâche complexe si l'on ne sait pas par où commencer. Il est toujours recommandé d'aborder le problème suivant le principe du "bas vers le haut" : commencez par les pods, puis passez au service et à l'Ingress. Les méthodes de débogage décrites dans cet article peuvent également s'appliquer à d'autres objets, tels que :
- les Jobs et CronJobs défaillants ;
- les StatefulSets et DaemonSets.
Je tiens à remercier , et pour leurs précieuses observations et contributions.
P.S. de l'auteur
Lisez aussi dans notre blog :
- «»;
- «»;
- «»;
- «».
Source : habr.com
