Visuelle Fehlerbehebung für Kubernetes

Hinweis perev. : Dieser Artikel ist Teil des frei verfügbaren Materials aus dem learnk8s- Projekt, in dem Sie lernen , wie Sie mit Kubernetes-Unternehmen und einzelnen Administratoren arbeiten. Darin gibt Daniele Polencic, der Projektmanager, eine klare Anweisung, welche Schritte bei allgemeinen Problemen für Anwendungen im K8s-Cluster zu unternehmen sind.



TL; DR: Hier ist ein Diagramm, das Ihnen beim Debuggen der Bereitstellung in Kubernetes hilft:



Flussdiagramm zum Auffinden und Beheben von Fehlern in einem Cluster. Im Original (auf Englisch) ist es als PDF und als Bild verfügbar.

Wenn Sie eine Anwendung auf Kubernetes bereitstellen, müssen Sie normalerweise drei Komponenten definieren:

  • Die Bereitstellung ist ein Rezept zum Erstellen von Kopien einer Anwendung namens Pods.
  • Service - ein interner Load Balancer, der den Datenverkehr auf die Pods verteilt;
  • Ingress - Eine Beschreibung, wie der Datenverkehr von der Außenwelt zum Service fließt.

Hier ist eine kurze grafische Zusammenfassung:

1) In Kubernetes empfangen Anwendungen Datenverkehr von der Außenwelt über zwei Ebenen von Load Balancern: interne und externe.



2) Der interne Balancer heißt Service, der externe - Ingress.



3) Die Bereitstellung erstellt Pods und überwacht sie (sie werden nicht manuell erstellt).



Angenommen, Sie möchten eine einfache Anwendung a la Hello World bereitstellen. Die YAML-Konfiguration dafür sieht folgendermaßen aus:

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: / 

Die Definition ist ziemlich lang und es ist leicht zu verwechseln, wie die Komponenten zueinander in Beziehung stehen.

Zum Beispiel:

  • Wann sollten Sie Port 80 und wann - 8080 verwenden?
  • Soll ich für jeden Dienst einen neuen Port erstellen, damit keine Konflikte auftreten?
  • Sind Markennamen wichtig? Sollten sie überall gleich sein?

Bevor wir uns auf das Debuggen konzentrieren, wollen wir uns erinnern, wie die drei Komponenten zueinander in Beziehung stehen. Beginnen wir mit Bereitstellung und Service.

Connection Deployment'a und Service'a


Sie werden überrascht sein, aber Deployments und Service sind in keiner Weise miteinander verbunden. Stattdessen verweist der Dienst direkt auf Pods, die die Bereitstellung umgehen.

Aus diesem Grund interessieren wir uns für die Beziehung zwischen Pods und Services. Drei Dinge zu beachten:

  1. Ein Service- selector muss mit mindestens einem Pod-Etikett übereinstimmen.
  2. targetPort muss mit dem containerPort Containers im Pod übereinstimmen.
  3. port Service kann alles sein. Verschiedene Dienste können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben.

Das folgende Diagramm zeigt alle oben genannten Punkte in grafischer Form:

1) Stellen Sie sich vor, der Dienst leitet den Verkehr zu einem bestimmten Pod weiter:



2) Beim Erstellen eines Pods müssen Sie containerPort für jeden Container in den Pods angeben:



3) Beim Erstellen des Dienstes müssen Sie port und targetPort angeben. Aber welches verbindet sich mit dem Container?



4) Über targetPort . Es sollte mit containerPort übereinstimmen.



5) Nehmen wir an, Port 3000 ist im Container offen, dann sollte der targetPort Wert gleich sein.



In der YAML-Datei müssen die Bezeichnungen und ports / targetPort übereinstimmen:

 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 # <<< 

Was ist mit dem track: canary oben im Bereich Bereitstellung? Sollte es passen?

Diese Bezeichnung bezieht sich auf die Bereitstellung und wird vom Dienst nicht zum Weiterleiten des Datenverkehrs verwendet. Mit anderen Worten, es kann gelöscht oder ein anderer Wert zugewiesen werden.

Was ist mit dem matchLabels Selektor?

Es sollte immer mit den Beschriftungen des Pods übereinstimmen , da es von der Bereitstellung zum Verfolgen von Pods verwendet wird.

Angenommen, Sie haben die richtigen Änderungen vorgenommen. Wie prüfe ich sie?

Sie können die Pod-Bezeichnung mit dem folgenden Befehl überprüfen:

 kubectl get pods --show-labels 

Oder, wenn Pods zu mehreren Anwendungen gehören:

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

Wobei any-name=my-app die any-name: my-app .

Gibt es irgendwelche Schwierigkeiten?

Sie können sich mit dem Pod verbinden! Verwenden Sie dazu den Befehl port-forward in kubectl. Hiermit können Sie eine Verbindung zum Dienst herstellen und die Verbindung überprüfen.

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

Hier:

  • service/<service name> - Dienstname; in unserem Fall ist es my-service ;
  • 3000 - der Port, den Sie auf dem Computer öffnen möchten;
  • 80 - im port des Dienstes angegebener port .

Wenn Sie eine Verbindung herstellen konnten, sind die Einstellungen korrekt.

Wenn die Verbindung nicht hergestellt werden konnte, liegt ein Problem mit den Beschriftungen vor oder die Anschlüsse stimmen nicht überein.

Verbindung von Service und Ingress


Der nächste Schritt zum Bereitstellen des Zugriffs auf die Anwendung bezieht sich auf die Konfiguration von Ingress. Ingress sollte wissen, wie der Service zu finden ist, und dann die Pods finden und den Verkehr zu ihnen leiten. Ingress findet den gewünschten Dienst nach Name und offenem Port.

In der Beschreibung von Ingress und Service müssen zwei Parameter übereinstimmen:

  1. servicePort in Ingress muss mit dem servicePort in Service übereinstimmen.
  2. serviceName in Ingress muss mit dem serviceName in Service übereinstimmen.

Das folgende Diagramm fasst die Verbindung der Ports zusammen:

1) Wie Sie bereits wissen, überwacht Service einen bestimmten port :



2) Ingress hat einen Parameter namens servicePort :



3) Dieser Parameter ( servicePort ) sollte immer mit dem port in der Service-Definition übereinstimmen:



4) Wenn unter Service der Port 80 angegeben ist, muss servicePort ebenfalls 80 sein:



In der Praxis müssen Sie folgende Zeilen beachten:

 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: / 

Wie überprüfe ich, ob Ingress funktioniert?

Sie können die Methode mit kubectl port-forward , müssen jedoch anstelle des Dienstes eine Verbindung zum Ingress-Controller herstellen.

Zuerst müssen Sie den Namen des Pods mit dem Ingress-Controller herausfinden:

 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 

Suchen Sie den Ingress-Pod (er verweist möglicherweise auf einen anderen Namespace) und führen Sie den Befehl describe , um die Portnummern zu ermitteln:

 kubectl describe pod nginx-ingress-controller-6fc5bcc \ --namespace kube-system \ | grep Ports Ports: 80/TCP, 443/TCP, 18080/TCP 

Zum Schluss verbinden Sie sich mit dem Pod:

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

Jedes Mal, wenn Sie eine Anforderung an Port 3000 auf dem Computer senden, wird diese mit dem Ingress-Controller an Port 80 des Pods umgeleitet. Wenn Sie http: // localhost: 3000 aufrufen, sollte die von der Anwendung erstellte Seite angezeigt werden.

Port-Zusammenfassung


Erinnern wir uns noch einmal, welche Ports und Labels übereinstimmen sollten:

  1. Der Selektor in der Service-Definition muss mit der Pod-Bezeichnung übereinstimmen.
  2. targetPort in der Service-Definition muss mit dem containerPort Containers im Pod übereinstimmen.
  3. port in der Definition von Service kann alles sein. Verschiedene Dienste können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben.
  4. servicePort Ingress muss mit dem port in der Service-Definition übereinstimmen.
  5. Der Servicename muss mit dem Feld serviceName in Ingress übereinstimmen.

Leider reicht es nicht aus, zu wissen, wie Ihre YAML-Konfiguration richtig strukturiert wird.

Was passiert, wenn etwas schief geht?

Vielleicht startet der Pod nicht oder er stürzt ab.

3 Schritte zur Behebung von Anwendungsfehlern in Kubernetes


Bevor Sie ein Deployment debuggen, müssen Sie wissen, wie Kubernetes funktioniert.

Da jede auf K8 heruntergeladene Anwendung drei Komponenten enthält, sollten sie in einer bestimmten Reihenfolge von unten nach unten getestet werden.

  1. Zuerst müssen Sie sicherstellen, dass die Pods funktionieren, dann ...
  2. Überprüfen Sie, ob der Service Datenverkehr an die Pods liefert, und führen Sie dann Folgendes aus:
  3. Überprüfen Sie, ob Ingress richtig konfiguriert ist.

Visuelle Darstellung:

1) Starten Sie die Suche nach Problemen sollte von unten sein. Überprüfen Sie zunächst, ob die Pods Ready und ausgeführt werden:



2) Wenn die Pods Ready , sollten Sie herausfinden, ob der Dienst den Datenverkehr zwischen den Pods verteilt:



3) Schließlich müssen Sie die Verbindung zwischen dem Dienst und Ingress analysieren:



1. Diagnostik von Schoten


In den meisten Fällen liegt das Problem beim Pod. Stellen Sie sicher, dass die Pods betriebsbereit sind. Sie können dies mit dem folgenden Befehl überprüfen:

 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 

In der Ausgabe des obigen Befehls wird der letzte Pod als " Running und " Ready , bei den beiden anderen nicht.

Wie kann man verstehen, was schief gelaufen ist?

Es gibt vier nützliche Befehle zur Diagnose von Pods:

  1. kubectl logs < pod'> können Sie Protokolle aus Containern in pod extrahieren.
  2. kubectl describe pod < pod'> können Sie eine Liste der mit dem Pod verbundenen Ereignisse anzeigen.
  3. kubectl get pod < pod'> können Sie die YAML-Konfiguration des in Kubernetes gespeicherten kubectl get pod < pod'> abrufen.
  4. kubectl exec -ti < pod'> bash können Sie eine interaktive Befehlsshell in einem der Pod-Container ausführen

Welches soll ich wählen?

Tatsache ist, dass es kein universelles Team gibt. Eine Kombination von diesen sollte verwendet werden.

Häufige Probleme mit der Kapsel


Es gibt zwei Haupttypen von Pod-Fehlern: Startfehler und Laufzeitfehler.

Startfehler:

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

Laufzeitfehler:

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

Einige Fehler sind häufiger als andere. Hier sind einige häufige Fehler und deren Behebung.

ImagePullBackOff


Dieser Fehler tritt auf, wenn Kubernetes kein Bild für einen der Pod-Container abrufen kann. Hier sind die drei häufigsten Gründe dafür:

  1. Der Bildname wurde falsch angegeben. Sie haben beispielsweise einen Fehler gemacht oder das Bild ist nicht vorhanden.
  2. Es wurde ein nicht vorhandenes Tag für das Bild angegeben.
  3. Das Image wird in einer privaten Registrierung gespeichert und Kubernetes hat keine Berechtigung, darauf zuzugreifen.

Die ersten beiden Gründe sind leicht zu beseitigen - korrigieren Sie einfach den Bildnamen und das Tag. In letzterem Fall müssen Sie die Anmeldeinformationen für die private Registrierung in Secret eingeben und in Pods Links hinzufügen. Die Kubernetes-Dokumentation enthält ein Beispiel dafür, wie dies getan werden kann.

CrashLoopBackOff


Kubenetes löst einen CrashLoopBackOff-Fehler aus, wenn der Container nicht gestartet werden kann. Dies passiert normalerweise, wenn:

  1. In der Anwendung ist ein Fehler aufgetreten, der den Start verhindert.
  2. Der Container ist falsch konfiguriert .
  3. Der Liveness-Test ist zu oft fehlgeschlagen.

Sie müssen versuchen, die Protokolle aus dem Container abzurufen, um den Grund für den Fehler herauszufinden. Wenn der Zugriff auf die Protokolle schwierig ist, weil der Container zu schnell neu gestartet wird, können Sie den folgenden Befehl verwenden:

 kubectl logs <pod-name> --previous 

Es zeigt Fehlermeldungen von einer früheren Container-Reinkarnation an.

RunContainerError


Dieser Fehler tritt auf, wenn der Container nicht gestartet werden kann. Es entspricht dem Moment vor dem Start der Anwendung. Normalerweise ist die Ursache eine falsche Konfiguration, zum Beispiel:

  • Es wird versucht, ein nicht vorhandenes Volume bereitzustellen, z. B. ConfigMap oder Secrets.
  • Versuchen Sie, ein schreibgeschütztes Volume als Lese- / Schreibzugriff bereitzustellen.

Der kubectl describe pod <pod-name> eignet sich gut zur Analyse solcher Fehler.

Hülsen ausstehend


Nach der Erstellung verbleibt der Pod im Status Pending .

Warum passiert das?

Hier sind die möglichen Gründe (ich gehe davon aus, dass der Scheduler gut funktioniert):

  1. Der Cluster verfügt nicht über genügend Ressourcen, z. B. Prozessorleistung und Arbeitsspeicher, um den Pod auszuführen.
  2. Das ResourceQuota Objekt wird im entsprechenden Namespace installiert, und das Erstellen eines Pods führt dazu, dass der Namespace das Kontingent überschreitet.
  3. Der Pod ist an Pending PersistentVolumeClaim gebunden.

In diesem Fall wird empfohlen, den Befehl kubectl describe und den Abschnitt Events überprüfen:

 kubectl describe pod <pod name> 

Bei Fehlern im Zusammenhang mit ResourceQuotas wird empfohlen, die Clusterprotokolle mit dem Befehl anzuzeigen

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

Hülsen nicht bereit


Wenn der Pod als "Wird ausgeführt" aufgeführt ist, sich jedoch nicht im Status " Ready , ist die Bereitschaftsprüfung nicht erfolgreich.

In diesem Fall stellt der Pod keine Verbindung zum Dienst her und der Datenverkehr fließt nicht dorthin. Der Readiness-Test ist aufgrund von Anwendungsproblemen fehlgeschlagen. In diesem Fall müssen Sie den Abschnitt " Events " in der Ausgabe des kubectl describe analysieren, um den Fehler zu finden.

2. Diagnose von Diensten


Wenn die Pods als " Running und " Ready , die Anwendung jedoch weiterhin nicht reagiert, sollten Sie die Diensteinstellungen überprüfen.

Dienste sind abhängig von ihren Bezeichnungen an der Weiterleitung des Datenverkehrs an Pods beteiligt. Überprüfen Sie daher zunächst, wie viele Pods mit dem Service zusammenarbeiten. Dazu können Sie die Endpunkte im Service überprüfen:

 kubectl describe service <service-name> | grep Endpoints 

Endpunkt ist ein Wertepaar der Form <IP-:> , und mindestens ein solches Paar muss in der Ausgabe vorhanden sein (dh, mindestens ein Pod arbeitet mit dem Service zusammen).

Wenn der Abschnitt Endpoins leer ist, sind zwei Optionen möglich:

  1. Es gibt keine Pods mit der richtigen Bezeichnung (Hinweis: Überprüfen Sie, ob der Namespace richtig ausgewählt ist).
  2. Es liegt ein Fehler in den Dienstetiketten im Selektor vor.

Wenn Sie eine Liste mit Endpunkten sehen, aber immer noch nicht auf die Anwendung zugreifen können, ist der wahrscheinliche Schuldige der Fehler in targetPort in der Servicebeschreibung.

Wie überprüfe ich die Servicefreundlichkeit?

Unabhängig von der Art des Dienstes können Sie mit dem kubectl port-forward eine Verbindung herstellen:

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

Hier:

  • <service-name> - der Name des Dienstes;
  • 3000 - der Port, den Sie auf dem Computer öffnen;
  • 80 - Port auf der Serviceseite.

3. Ingress-Diagnose


Wenn Sie bis zu diesem Ort gelesen haben, dann:

  • Die Pods sind als " Running und " Ready .
  • Der Dienst verteilt den Datenverkehr erfolgreich auf die Pods.

Sie können jedoch immer noch nicht auf die Anwendung zugreifen.

Dies bedeutet, dass der Ingress-Controller höchstwahrscheinlich falsch konfiguriert ist. Da der Ingress-Controller eine Komponente eines Drittanbieters im Cluster ist, gibt es je nach Typ verschiedene Debugging-Methoden.

Bevor Sie jedoch zum Konfigurieren von Ingress auf spezielle Tools zurückgreifen, können Sie etwas ganz Einfaches tun. Ingress verwendet serviceName und servicePort , um eine Verbindung zum Dienst servicePort . Sie müssen überprüfen, ob sie richtig konfiguriert sind. Sie können dies mit dem folgenden Befehl tun:

 kubectl describe ingress <ingress-name> 

Wenn die Spalte Backend leer ist, besteht eine hohe Wahrscheinlichkeit eines Konfigurationsfehlers. Wenn die Backends vorhanden sind, aber immer noch kein Zugriff auf die Anwendung besteht, kann das Problem folgende Ursachen haben:

  • Einstellungen für die Ingress-Erreichbarkeit aus dem öffentlichen Internet;
  • Einstellungen für die Cluster-Zugänglichkeit aus dem öffentlichen Internet.

Sie können Infrastrukturprobleme identifizieren, indem Sie eine direkte Verbindung zum Ingress-Pod herstellen. Suchen Sie dazu zuerst den Pod des Ingress-Controllers (möglicherweise in einem anderen Namespace):

 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 

Verwenden Sie den Befehl describe , um den Port festzulegen:

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

Zum Schluss verbinden Sie sich mit dem Pod:

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

Jetzt werden alle Anforderungen für den Port 3000 auf dem Computer an den Port 80-Pod umgeleitet.

Funktioniert es jetzt

  • Wenn ja, liegt das Problem in der Infrastruktur. Es muss genau herausgefunden werden, wie der Datenverkehr zum Cluster geleitet wird.
  • Wenn nicht, liegt das Problem beim Ingress-Controller.

Wenn Sie den Ingress-Controller nicht zum Laufen bringen können, müssen Sie ihn debuggen.

Es gibt viele verschiedene Arten von Ingress-Controllern. Am beliebtesten sind Nginx, HAProxy, Traefik und andere. (Weitere Informationen zu vorhandenen Lösungen finden Sie in unserem Testbericht .) Verwenden Sie die Anleitung zur Fehlerbehebung in der Dokumentation des entsprechenden Controllers. Da Ingress Nginx der beliebteste Ingress-Controller ist, enthält dieser Artikel einige Tipps zur Behebung verwandter Probleme.

Debuggen eines Ingress Nginx-Controllers



Das Ingress-Nginx-Projekt hat ein offizielles Plugin für Kubectl . Der kubectl ingress-nginx kann verwendet werden, um:

  • Analyse von Logs, Backends, Zertifikaten usw .;
  • Verbindung zu Ingress;
  • Studieren der aktuellen Konfiguration.

Die folgenden drei Teams helfen Ihnen dabei:

  • kubectl ingress-nginx lint - prüft nginx.conf ;
  • kubectl ingress-nginx backend - untersucht das Backend (ähnlich wie kubectl describe ingress <ingress-name> );
  • kubectl ingress-nginx logs - prüft logs.

Beachten Sie, dass es in einigen Fällen erforderlich sein kann, den richtigen Namespace für den Ingress-Controller mithilfe des --namespace <name> .

Zusammenfassung


Die Diagnose von Kubernetes kann eine entmutigende Aufgabe sein, wenn Sie nicht wissen, wo Sie anfangen sollen. Das Problem sollte immer nach dem Bottom-up-Prinzip angegangen werden: Beginnen Sie mit Pods und gehen Sie dann zu Service und Ingress. Die im Artikel beschriebenen Debugging-Methoden können auf andere Objekte angewendet werden, z.

  • Leerlaufjobs und CronJobs;
  • StatefulSets und DaemonSets.

Vielen Dank an Gergely Risko , Daniel Weibel und Charles Christyraj für wertvolle Kommentare und Ergänzungen.

PS vom Übersetzer


Lesen Sie auch in unserem Blog:

Source: https://habr.com/ru/post/de484954/


All Articles