Un guide visuel pour dépanner Kubernetes

Noter. trad.: Cet article fait partie des documents du projet publiés dans le domaine public apprendrek8s, des entreprises de formation et des administrateurs individuels pour travailler avec Kubernetes. Dans ce document, Daniele Polencic, chef de projet, partage des instructions visuelles sur les mesures à prendre en cas de problèmes généraux avec les applications exécutées sur le cluster K8s.

Un guide visuel pour dépanner Kubernetes

TL;DR : voici un schéma qui vous aidera à déboguer le déploiement dans Kubernetes :

Un guide visuel pour dépanner Kubernetes

Organigramme permettant de rechercher et de corriger les erreurs dans un cluster. L'original (en anglais) est disponible sur PDF и comme image.

Lors du déploiement d'une application sur Kubernetes, vous devez généralement définir trois composants :

  • Déploiement - c'est une sorte de recette pour créer des copies de l'application, appelées pods ;
  • Service — équilibreur de charge interne qui répartit le trafic entre les pods ;
  • Entrée — une description de la manière dont le trafic sera acheminé du monde extérieur vers le Service.

Voici un bref résumé graphique :

1) Dans Kubernetes, les applications reçoivent le trafic du monde extérieur via deux couches d'équilibreurs de charge : interne et externe.

Un guide visuel pour dépanner Kubernetes

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

Un guide visuel pour dépanner Kubernetes

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

Un guide visuel pour dépanner Kubernetes

Disons que vous souhaitez déployer une application simple à la Bonjour tout le monde. La configuration YAML ressemblera à 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 tromper sur la manière dont les composants sont liés les uns aux autres.

Par exemple:

  • Quand devez-vous utiliser le port 80 et quand devez-vous utiliser le 8080 ?
  • Dois-je créer un nouveau port pour chaque service afin qu'ils n'entrent pas en conflit ?
  • Les noms d’étiquettes sont-ils importants ? Doivent-ils être les mêmes partout ?

Avant de nous concentrer sur le débogage, rappelons les relations entre les trois composants. Commençons par le déploiement et le service.

Relation entre le déploiement et le service

Vous serez surpris, mais Déploiement et Service ne sont en aucun cas liés. Au lieu de cela, le service pointe directement vers les pods, en contournant le déploiement.

Ainsi, nous nous intéressons à la manière dont les Pods et les Services sont liés les uns aux autres. Trois choses à retenir :

  1. Sélecteur (selector) pour le service doit correspondre à au moins une étiquette de pod.
  2. targetPort doit correspondre containerPort conteneur à l’intérieur du Pod.
  3. port Le service peut être n'importe quoi. Différents services peuvent utiliser le même port car ils ont des adresses IP différentes.

Le diagramme suivant représente tout ce qui précède sous forme graphique :

1) Imaginez que le service dirige le trafic vers un certain pod :

Un guide visuel pour dépanner Kubernetes

2) Lors de la création d'un pod, vous devez préciser containerPort pour chaque contenant en dosettes :

Un guide visuel pour dépanner Kubernetes

3) Lors de la création d'un service, vous devez préciser port и targetPort. Mais lequel est utilisé pour se connecter au conteneur ?

Un guide visuel pour dépanner Kubernetes

4) Par targetPort. Cela doit correspondre containerPort.

Un guide visuel pour dépanner Kubernetes

5) Disons que le port 3000 est ouvert dans le conteneur. Alors la valeur targetPort devrait être le même.

Un guide visuel pour dépanner Kubernetes

Dans le fichier YAML, les étiquettes et ports / targetPort doit 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 en haut de la section Déploiement ? Est-ce que ça devrait correspondre ?

Cette étiquette est spécifique au déploiement et n'est pas utilisée par le service pour acheminer le trafic. En d’autres termes, il peut être supprimé ou lui attribuer une valeur différente.

Qu'en est-il du sélecteur matchLabels?

Il doit toujours correspondre aux étiquettes du Pod, car il est utilisé par le déploiement pour suivre les pods.

Supposons que vous ayez effectué les modifications correctes. Comment les vérifier ?

Vous pouvez vérifier l'étiquette du pod avec la commande suivante :

kubectl get pods --show-labels

Ou, si les pods appartiennent à plusieurs applications :

kubectl get pods --selector any-name=my-app --show-labels

any-name=my-app est une étiquette any-name: my-app.

Reste-t-il des difficultés ?

Vous pouvez vous connecter au pod ! Pour ce faire, vous devez utiliser la commande port-forward dans Kubectl. Il vous permet de vous connecter au service et de vérifier la connexion.

kubectl port-forward service/<service name> 3000:80

Ici:

  • service/<service name> - Nom du service; dans notre cas c'est my-service;
  • 3000 est le port qui doit être ouvert sur l'ordinateur ;
  • 80 - port spécifié dans le champ port service.

Si la connexion a été établie, les paramètres sont corrects.

Si la connexion échoue, il y a un problème avec les étiquettes ou les ports ne correspondent pas.

Relation entre le service et l'entrée

La prochaine étape pour fournir l'accès à l'application consiste à configurer Ingress. Ingress doit savoir comment trouver un service, puis trouver des pods et diriger le trafic vers eux. Ingress trouve le service requis par nom et port ouvert.

Dans la description d'Ingress et de Service, deux paramètres doivent correspondre :

  1. servicePort dans Ingress doit correspondre au paramètre port en service;
  2. serviceName dans Ingress doit correspondre au champ name en service.

Le diagramme suivant résume les connexions des ports :

1) Comme vous le savez déjà, Service écoute un certain port:

Un guide visuel pour dépanner Kubernetes

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

Un guide visuel pour dépanner Kubernetes

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

Un guide visuel pour dépanner Kubernetes

4) Si le port 80 est spécifié dans Service, alors il faut que servicePort était également égal à 80 :

Un guide visuel pour dépanner Kubernetes

En pratique, il faut faire 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 Ingress est en cours d’exécution ?

Vous pouvez utiliser la méthode avec kubectl port-forward, mais au lieu du service, vous devez vous connecter au contrôleur Ingress.

Vous devez d’abord 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

Recherchez le pod Ingress (il peut se trouver dans un espace de noms différent) et exécutez la commande describepour 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/TCP

Enfin, connectez-vous au pod :

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Désormais, chaque fois que vous envoyez une requête au port 3000 de votre ordinateur, elle sera transmise au port 80 du pod avec le contrôleur Ingress. En allant à http://localhost:3000, vous devriez voir la page générée par l'application.

Résumé des ports

Rappelons encore une fois quels ports et étiquettes doivent correspondre :

  1. Le sélecteur dans la définition du service doit correspondre à l'étiquette du pod ;
  2. targetPort dans la définition Le service doit correspondre containerPort récipient à l'intérieur d'une dosette ;
  3. port dans la définition, le service peut être n'importe quoi. Différents services peuvent utiliser le même port car ils ont des adresses IP différentes ;
  4. servicePort L'entrée doit correspondre port dans la définition du Service ;
  5. Le nom du service doit correspondre au champ serviceName dans Entrée.

Malheureusement, il ne suffit pas de savoir structurer correctement une configuration YAML.

Que se passe-t-il lorsque les choses tournent mal ?

Le pod peut ne pas démarrer ou planter.

3 étapes pour diagnostiquer les problèmes d'application dans Kubernetes

Avant de commencer à déboguer votre déploiement, vous devez bien comprendre le fonctionnement de Kubernetes.

Étant donné que chaque application téléchargée dans K8 comporte trois composants, ils doivent être débogués dans un certain ordre, en commençant tout en bas.

  1. Vous devez d’abord vous assurer que les pods fonctionnent, puis...
  2. Vérifiez si le service fournit du trafic aux pods, puis...
  3. Vérifiez si Ingress est configuré correctement.

Représentation visuelle:

1) Vous devriez commencer à rechercher les problèmes par le bas. Vérifiez d'abord que les pods ont des statuts Ready и Running:

Un guide visuel pour dépanner Kubernetes

2) Si les dosettes sont prêtes (Ready), vous devez savoir si le service répartit le trafic entre les pods :

Un guide visuel pour dépanner Kubernetes

3) Enfin, vous devez analyser la connexion entre le service et l'Ingress :

Un guide visuel pour dépanner Kubernetes

1. Diagnostic des pods

Dans la plupart des cas, le problème est lié au pod. Assurez-vous que les pods sont répertoriés comme Ready и Running. Vous pouvez le vérifier 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 le résultat de la commande ci-dessus, le dernier pod est répertorié comme Running и Ready, cependant, ce n’est pas le cas des deux autres.

Comment comprendre ce qui n’a pas fonctionné ?

Il existe quatre commandes utiles pour diagnostiquer les pods :

  1. kubectl logs <имя pod'а> vous permet d'extraire les journaux des conteneurs dans un pod ;
  2. kubectl describe pod <имя pod'а> vous permet d'afficher une liste d'événements associés au pod ;
  3. kubectl get pod <имя pod'а> permet d'obtenir la configuration YAML d'un pod stocké dans Kubernetes ;
  4. kubectl exec -ti <имя pod'а> bash vous permet de lancer un shell de commande interactif dans l'un des conteneurs pod

Lequel devriez-vous choisir ?

Le fait est qu’il n’existe pas de commandement universel. Une combinaison de ces éléments doit être utilisée.

Problèmes typiques de pod

Il existe deux principaux types d'erreurs de pod : les erreurs de démarrage et les erreurs d'exécution.

Erreurs de démarrage :

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

Erreurs d'exécution :

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

Certaines erreurs sont plus courantes que d’autres. Voici quelques-unes des erreurs les plus courantes et comment les corriger.

ImagePullBackOff

Cette erreur se produit lorsque Kubernetes ne parvient pas à obtenir une image pour l'un des conteneurs de pods. Voici les trois raisons les plus courantes à cela :

  1. Le nom de l'image est incorrect - par exemple, vous avez fait une erreur ou l'image n'existe pas ;
  2. Une balise inexistante a été spécifiée pour l'image ;
  3. L'image est stockée dans un registre privé et Kubernetes n'est pas autorisé à y accéder.

Les deux premières raisons sont faciles à éliminer : il suffit de corriger le nom et la balise de l'image. Dans ce dernier cas, vous devez saisir les informations d'identification du registre fermé dans Secret et ajouter des liens vers celui-ci dans les pods. Dans la documentation Kubernetes il y a un exemple comment cela peut être fait.

Crash Loop Back Off

Kubenetes renvoie une erreur CrashLoopBackOff, si le conteneur ne peut pas démarrer. Cela se produit généralement lorsque :

  1. Il y a un bug dans l'application qui l'empêche de se lancer ;
  2. récipient mal configuré;
  3. Le test de vivacité a échoué trop souvent.

Vous devez essayer d'accéder aux journaux du conteneur pour connaître la raison de son échec. S'il est difficile d'accéder aux logs car le conteneur redémarre trop rapidement, vous pouvez utiliser la commande suivante :

kubectl logs <pod-name> --previous

Il affiche les messages d'erreur de l'incarnation précédente du conteneur.

ExécuterContainerError

Cette erreur se produit lorsque le conteneur ne démarre pas. Cela correspond au moment précédant le lancement de l'application. Cela est généralement dû à des paramètres incorrects, par exemple :

  • tenter de monter un volume inexistant tel que ConfigMap ou Secrets ;
  • une tentative de monter un volume en lecture seule en lecture-écriture.

L'équipe est bien adaptée pour analyser de telles erreurs kubectl describe pod <pod-name>.

Les pods sont à l'état En attente

Une fois créé, le pod reste dans l'état Pending.

Pourquoi cela se passe-t-il?

Voici les raisons possibles (je suppose que le planificateur fonctionne correctement) :

  1. Le cluster ne dispose pas de suffisamment de ressources, telles que la puissance de traitement et la mémoire, pour exécuter le pod.
  2. L'objet est installé dans l'espace de noms approprié ResourceQuota et la création d'un pod entraînera un dépassement de l'espace de noms du quota.
  3. Le pod est lié à En attente PersistentVolumeClaim.

Dans ce cas, il est recommandé d'utiliser la commande kubectl describe et regarde la section Events:

kubectl describe pod <pod name>

En cas d'erreurs liées à ResourceQuotas, il est recommandé de consulter les journaux du cluster à l'aide de la commande

kubectl get events --sort-by=.metadata.creationTimestamp

Les pods ne sont pas prêts

Si le pod est répertorié comme Running, mais n'est pas dans un état Ready, signifie vérifier son état de préparation (sonde de préparation) échoue.

Lorsque cela se produit, le pod ne se connecte pas au service et aucun trafic n’y circule. L’échec du test de préparation est dû à des problèmes dans l’application. Dans ce cas, pour trouver l'erreur, vous devez analyser la section Events dans la sortie de la commande kubectl describe.

2. Diagnostic des services

Si les pods sont répertoriés comme Running и Ready, mais il n'y a toujours pas de réponse de l'application, vous devez vérifier les paramètres du service.

Les services sont responsables de l'acheminement du trafic vers les pods en fonction de leurs étiquettes. Par conséquent, la première chose que vous devez faire est de vérifier combien de pods fonctionnent avec le service. Pour ce faire, vous pouvez vérifier les points de terminaison du service :

kubectl describe service <service-name> | grep Endpoints

Le point final est une paire de valeurs de la forme <IP-адрес:порт>, et au moins une de ces paires doit être présente dans la sortie (c'est-à-dire qu'au moins un pod fonctionne avec le service).

Si la section Endpoins vide, deux options sont possibles :

  1. il n'y a aucun pod avec le bon label (indice : vérifiez si l'espace de noms est correctement sélectionné) ;
  2. Il y a une erreur dans les étiquettes de service dans le sélecteur.

Si vous voyez une liste de points de terminaison mais que vous ne parvenez toujours pas à accéder à l'application, le coupable est probablement un bug dans targetPort dans 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 s'y connecter :

kubectl port-forward service/<service-name> 3000:80

Ici:

  • <service-name> - Nom du service;
  • 3000 est le port que vous ouvrez sur l'ordinateur ;
  • 80 - port côté service.

3. Diagnostics d'entrée

Si vous avez lu jusqu'ici, alors :

  • les dosettes sont répertoriées comme Running и Ready;
  • le service répartit avec succès le trafic entre les pods.

Cependant, vous ne parvenez toujours pas à accéder à l'application.

Cela signifie que le contrôleur Ingress n'est probablement pas configuré correctement. Le contrôleur Ingress étant un composant tiers du cluster, il existe différentes méthodes de débogage en fonction de son type.

Mais avant de recourir à des outils spéciaux pour configurer Ingress, vous pouvez faire quelque chose de très simple. Utilisations d'entrée serviceName и servicePort pour vous connecter au service. Vous devez vérifier s'ils sont correctement configurés. Vous pouvez le faire en utilisant la commande :

kubectl describe ingress <ingress-name>

Si colonne Backend vide, il existe une forte probabilité d’erreur de configuration. Si les backends sont en place, mais que l’application n’est toujours pas accessible, alors le problème peut être lié à :

  • Accédez aux paramètres d’accessibilité à partir de l’Internet public ;
  • paramètres d'accessibilité du cluster à partir de l'Internet public.

Vous pouvez identifier les problèmes liés à l'infrastructure en vous connectant directement au module Ingress. Pour ce faire, recherchez d'abord le pod Ingress Controller (il peut se trouver dans un espace de noms différent) :

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 describepour définir le port :

kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system 
 | grep Ports

Enfin, connectez-vous au pod :

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

Désormais, toutes les requêtes vers le port 3000 de l'ordinateur seront redirigées vers le port 80 du pod.

Est-ce que ça marche maintenant ?

  • Si oui, le problème vient de l’infrastructure. Il est nécessaire de savoir exactement comment le trafic est acheminé vers le cluster.
  • Sinon, le problème vient du contrôleur Ingress.

Si vous ne parvenez pas à faire fonctionner le contrôleur Ingress, vous devrez le déboguer.

Il existe de nombreuses variétés de contrôleurs Ingress. Les plus populaires sont Nginx, HAProxy, Traefik, etc. (pour plus d'informations sur les solutions existantes, voir notre avis - environ. trad.) Vous devez vous référer au guide de dépannage dans la documentation du contrôleur concerné. Parce que le Entrée Nginx est le contrôleur Ingress le plus populaire, nous avons inclus quelques conseils dans l'article pour résoudre les problèmes qui y sont liés.

Débogage du contrôleur Ingress Nginx

Le projet Ingress-nginx a un officiel plugin pour Kubectl. Équipe kubectl ingress-nginx peut être utilisé pour:

  • analyse des logs, backends, certificats, etc. ;
  • connexions à Ingress ;
  • étudier la configuration actuelle.

Les trois commandes suivantes vous y aideront :

  • kubectl ingress-nginx lint - des chèques nginx.conf;
  • kubectl ingress-nginx backend — explore le backend (similaire à kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs - vérifie les journaux.

Notez que dans certains cas, vous devrez peut-être spécifier l'espace de noms correct pour le contrôleur Ingress à l'aide de l'indicateur --namespace <name>.

Résumé

Le dépannage de Kubernetes peut être difficile si vous ne savez pas par où commencer. Vous devez toujours aborder le problème de bas en haut : commencez par les pods, puis passez au service et à Ingress. Les techniques de débogage décrites dans cet article peuvent être appliquées à d'autres objets, tels que :

  • Travaux inactifs et CronJobs ;
  • StatefulSets et DaemonSets.

J'exprime ma gratitude Gergély Risko, Daniel Weibel и Charles Christyraj pour de précieux commentaires et ajouts.

PS du traducteur

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire