Hinweis.: Dieser Artikel ist Teil der im Rahmen des Projekts veröffentlichten Materialien, die öffentlich zugänglich sind. , die Administratoren und Einzelpersonen in der Arbeit mit Kubernetes schulen. Daniele Polencic, der Projektleiter, bietet in diesem Artikel eine anschauliche Anleitung zu den Schritten, die bei allgemeinen Problemen von in einem K8s-Cluster betriebenen Anwendungen zu unternehmen sind.

TL;DR: Hier ist ein Schema, das Ihnen hilft, das Deployment in Kubernetes zu debuggen:
Flussdiagramm zur Fehlersuche und -behebung im Cluster. In der Originalversion (auf Englisch) ist es verfügbar in und .
Beim Deployment einer Anwendung in Kubernetes müssen normalerweise drei Komponenten definiert werden:
- Deployment — ein Rezept zur Erstellung von Anwendungsduplikaten, den sogenannten Pods;
- Service — ein interner Lastenausgleich, der den Datenverkehr auf die Pods verteilt;
- Ingress — eine Beschreibung, wie der Datenverkehr aus der externen Welt zum Service gelangt.
Hier ist eine kurze grafische Zusammenfassung:
1) In Kubernetes erhalten Anwendungen Datenverkehr aus der externen Welt über zwei Schichten von Lastenausgleichern: intern und extern.

2) Der interne Lastenausgleich wird als Service bezeichnet, der externe als Ingress.

3) Das Deployment erstellt Pods und überwacht sie (die Pods werden nicht manuell erstellt).

Angenommen, Sie möchten eine einfache Anwendung wie Hello Worldbereitstellen. Die YAML-Konfiguration dafür könnte folgendermaßen aussehen:
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 kann leicht verwirrend werden, wie die Komponenten miteinander verbunden sind.
Zum Beispiel:
- Wann sollte Port 80 und wann Port 8080 verwendet werden?
- Sollte für jeden Dienst ein neuer Port erstellt werden, um Konflikte zu vermeiden?
- Spielen die Namen der Labels eine Rolle? Müssen sie überall gleich sein?
Bevor wir uns auf das Debugging konzentrieren, lassen Sie uns daran erinnern, wie die drei Komponenten miteinander verbunden sind. Beginnen wir mit Deployment und Service.
Die Beziehung zwischen Deployment und Service
Sie werden überrascht sein, aber Deployments und Services sind nicht miteinander verbunden. Stattdessen verweist der Service direkt auf die Pods, ohne den Deployment-Weg zu nehmen.
In diesem Zusammenhang interessiert uns, wie Pods und Services miteinander verbunden sind. Es gibt drei wichtige Punkte zu beachten:
- Der Selector (
selector) des Services muss mit mindestens einem Label des Pods übereinstimmen. -
targetPortmuss übereinstimmen mitcontainerPortdes Containers innerhalb des Pods. -
portDer Service kann beliebig sein. Verschiedene Services können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben.
Das folgende Diagramm stellt alles oben Genannte visuell dar:
1) Stellen wir uns vor, der Service leitet den Datenverkehr an einen bestimmten Pod:

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

3) Beim Erstellen eines Services müssen Sie angeben port und targetPort. Aber über welchen von ihnen erfolgt die Verbindung zum Container?

4) Über targetPort. Dies muss übereinstimmen mit containerPort.

5) Angenommen, im Container ist Port 3000 geöffnet. Dann muss der Wert targetPort gleich sein.

In der YAML-Datei müssen die Labels 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 # <<< Wie steht es um das Label track: canary im oberen Bereich des Deployments? Sollte es übereinstimmen?
Dieses Label gehört zum Deployment und wird vom Service nicht zur Routen von Traffic verwendet. Mit anderen Worten, es kann gelöscht oder umbenannt werden.
Wie sieht es mit dem Selector aus? matchLabels?
Er sollte immer mit den Labels des Pods übereinstimmen,da er vom Deployment zum Tracking der Pods verwendet wird.
Angenommen, Sie haben die richtigen Änderungen vorgenommen. Wie überprüfen Sie dies?
Das Label der Pods kann mit dem folgenden Befehl überprüft werden:
kubectl get pods --show-labelsOder, wenn die Pods mehreren Anwendungen gehören:
kubectl get pods --selector any-name=my-app --show-labels Dabei ist any-name=my-app — das ist das Label any-name: my-app.
Haben Sie noch Schwierigkeiten?
Sie können sich mit dem Pod verbinden! Dazu verwenden Sie den Befehl port-forward in kubectl. Er ermöglicht es Ihnen, sich mit dem Service zu verbinden und die Verbindung zu überprüfen.
kubectl port-forward service/ 3000:80Hier:
-
service/— der Name des Services; in unserem Fall ist dasmy-service; - 3000 — der Port, der auf dem Computer geöffnet werden muss;
- 80 — der Port, der im Feld
portdes Services angegeben ist.
Wenn die Verbindung erfolgreich hergestellt wurde, sind die Einstellungen korrekt.
Wenn die Verbindung nicht hergestellt werden konnte, liegt ein Problem mit den Labels oder den Portnummern vor.
Verbindung zwischen Service und Ingress
Der nächste Schritt, um den Zugriff auf die Anwendung zu ermöglichen, besteht darin, den Ingress einzurichten. Der Ingress muss wissen, wie er den Service finden kann, um dann die Pods zu finden und den Verkehr an sie weiterzuleiten. Der Ingress findet den benötigten Service nach Namen und offenem Port.
In der Beschreibung von Ingress und Service müssen zwei Parameter übereinstimmen:
-
servicePortim Ingress muss mit dem Parameter übereinstimmenportim Service; -
serviceNameim Ingress muss mit dem Feld übereinstimmennameim Service.
Das folgende Schema fasst die Portverbindungen zusammen:
1) Wie Sie bereits wissen, hört der Service auf einen bestimmten port:

2) Der Ingress hat einen Parameter, der genannt wird servicePort:

3) Dieser Parameter (servicePort) muss immer mit port in der Definition des Service übereinstimmen:

4) Wenn im Service der Port 80 festgelegt ist, muss auch servicePort gleich 80 sein:

In der Praxis sollten folgende Zeilen beachtet werden:
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üft man, ob der Ingress funktioniert?
Man kann die Methode mit kubectl port-forward, aber anstelle des Services sollte man sich mit dem Ingress-Controller verbinden.
Zunächst muss man 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 Finden Sie den Ingress-Pod (er kann zu einem anderen Namespace gehören) und führen Sie den Befehl describe, um die Portnummern zu erfahren:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPSchließlich verbinden Sie sich mit dem Pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemJetzt wird jeder Antrag, den Sie auf Port 3000 an Ihrem Computer senden, an Port 80 des Pods mit dem Ingress-Controller weitergeleitet. Gehen Sie zu , Sie sollten die von der Anwendung erzeugte Seite sehen.
Portübersicht
Lassen Sie uns noch einmal die Ports und Labels in Erinnerung rufen, die übereinstimmen müssen:
- Der Selector in der Service-Definition muss mit dem Label des Pods übereinstimmen;
-
targetPortin der Service-Definition muss übereinstimmen mitcontainerPortdem Container innerhalb des Pods; -
portin der Service-Definition kann beliebig sein. Verschiedene Services können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben; -
servicePortdes Ingress muss übereinstimmen mitportin der Service-Definition; - Der Name des Services muss mit dem Feld übereinstimmen
serviceNameim Ingress.
Leider reicht es nicht aus, zu wissen, wie man die YAML-Konfiguration richtig strukturiert.
Was passiert, wenn etwas schiefgeht?
Vielleicht startet der Pod nicht oder er stürzt ab.
3 Schritte zur Fehlersuche bei Anwendungen in Kubernetes
Bevor Sie mit dem Debuggen des Deployments beginnen, sollten Sie ein gutes Verständnis davon haben, wie Kubernetes funktioniert.
Da jede in K8s eingespielte Anwendung drei Komponenten hat, sollte die Fehlersuche in einer bestimmten Reihenfolge erfolgen, beginnend von unten.
- Zuerst müssen Sie sicherstellen, dass die Pods laufen, dann…
- Überprüfen Sie, ob der Service den Pods Traffic liefert, und danach…
- Überprüfen Sie die Konfiguration von Ingress.
Visuelle Darstellung:
1) Beginnen Sie die Fehlersuche von unten. Überprüfen Sie zunächst, ob die Pods den Status haben Bereit und Running:

2) Wenn die Pods bereit sind (Bereit), sollten Sie feststellen, ob der Service den Verkehr zwischen den Pods verteilt:

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

1. Diagnose der Pods
In den meisten Fällen hängt das Problem mit einem Pod zusammen. Stellen Sie sicher, dass die Pods als Bereit und Running. 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 Im obigen Befehl wird der letzte Pod als Running und Bereitaufgeführt, jedoch gilt dies nicht für die beiden anderen.
Wie erkennt man, dass etwas schiefgelaufen ist?
Es gibt vier nützliche Befehle zur Diagnose von Pods:
-
kubectl logserlaubt das Abrufen von Protokollen aus den Containern im Pod; -
kubectl describe podermöglicht die Anzeige der Ereignisliste, die mit dem Pod verbunden sind; -
kubectl get podermöglicht den Zugriff auf die YAML-Konfiguration des Pods, die in Kubernetes gespeichert ist; -
kubectl exec -ti bashermöglicht das Starten einer interaktiven Shell in einem der Container des Pods
Welche davon soll ich wählen?
Es gibt keine universelle Lösung. Es sollte eine Kombination ihrer verwendet werden.
Typische Probleme von Pods
Es gibt zwei Hauptarten von Pod-Fehlern: Startfehler (startup) und Laufzeitfehler (runtime).
Startfehler:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
InvalidImageName
Laufzeitfehler:
-
CrashLoopBackOff -
RunContainerError -
KillContainerError -
VerifyNonRootError -
RunInitContainerError -
CreatePodSandboxError -
ConfigPodSandboxError -
KillPodSandboxError -
SetupNetworkError -
TeardownNetworkError
Einige Fehler treten häufiger auf als andere. Hier sind einige der häufigsten Fehler und wie man sie beheben kann.
ImagePullBackOff
Dieser Fehler tritt auf, wenn Kubernetes nicht in der Lage ist, das Image für einen der Container im Pod abzurufen. Hier sind die drei häufigsten Ursachen dafür:
- Der Name des Images ist falsch angegeben – zum Beispiel haben Sie einen Schreibfehler gemacht oder das Image existiert nicht;
- Ein nicht existierendes Tag für das Image wurde angegeben;
- Das Image wird in einem privaten Registry gespeichert, und Kubernetes hat nicht die Berechtigung, darauf zuzugreifen.
Die ersten beiden Gründe lassen sich leicht beheben – man muss lediglich den Namen des Images und das Tag anpassen. Im letzteren Fall sind die Anmeldedaten für das private Repository in das Secret aufzunehmen und die entsprechenden Verlinkungen in die Pods einzufügen. In der Kubernetes-Dokumentation für die Umsetzung.
CrashLoopBackOff
Kubernetes gibt einen Fehler aus CrashLoopBackOff, wenn der Container nicht gestartet werden kann. Dies passiert normalerweise, wenn:
- Eine Anwendung einen Fehler enthält, der den Start verhindert;
- Container ;
- Der Liveness-Test ist zu oft fehlgeschlagen.
Man sollte versuchen, die Logs aus dem Container zu erreichen, um die Ursache des Fehlers herauszufinden. Falls der Zugriff auf die Logs schwierig ist, weil der Container zu schnell neu gestartet wird, kann man folgendes Kommando verwenden:
kubectl logs --previousDas gibt die Fehlermeldungen aus der vorherigen Instanz des Containers aus.
RunContainerError
Dieser Fehler tritt auf, wenn der Container nicht gestartet werden kann. Er entspricht dem Zeitpunkt vor dem Start der Anwendung. Die häufigste Ursache ist eine falsche Konfiguration, wie zum Beispiel:
- der Versuch, ein nicht existierendes Volume zu mounten, wie ConfigMap oder Secrets;
- Versuch, ein readonly-Laufwerk als read-write zu mounten.
Die folgende Kommandozeile eignet sich gut zur Analyse solcher Fehler: kubectl describe pod.
Pods im Status Pending
Nach der Erstellung bleibt der Pod im Status Pending.
Warum passiert das?
Hier sind mögliche Ursachen (ich gehe davon aus, dass der Scheduler normal funktioniert):
- Im Cluster sind nicht genügend Ressourcen wie Rechenleistung und Speicher verfügbar, um den Pod zu starten.
- Im entsprechenden Namespace ist ein Objekt installiert:
ResourceQuotaund die Erstellung des Pods würde dazu führen, dass der Namespace die Quota überschreitet. - Der Pod ist an Pending gebunden:
PersistentVolumeClaim.
In diesem Fall wird empfohlen, den Befehl zu verwenden: kubectl describe und den Abschnitt zu überprüfen: Veranstaltungen:
kubectl describe pod Bei Fehlern in Zusammenhang mit ResourceQuotas, wird empfohlen, die Cluster-Logs mit dem Befehl zu überprüfen:
kubectl get events --sort-by=.metadata.creationTimestampPods nicht im Status Ready
Wenn der Pod als Runninggilt, jedoch nicht im Status Bereitist, bedeutet das, dass die Bereitstellungsprüfung (readiness probe) nicht erfolgreich abgeschlossen wurde.
Wenn dies passiert, verbindet sich der Pod nicht mit dem Dienst, und es gibt keinen Datenverkehr. Der Fehler des Readiness-Tests wird durch Probleme in der Anwendung verursacht. In diesem Fall ist es notwendig, den Abschnitt zu analysieren, um den Fehler zu finden. Veranstaltungen im Ausgabeergebnis des Kommandos kubectl describe.
2. Diagnose der Dienste
Wenn die Pods als aufgeführt sind Running und Bereit, aber immer noch keine Antwort von der Anwendung kommt, sollten die Dienstkonfigurationen überprüft werden.
Dienste sind für die Weiterleitung des Datenverkehrs zu den Pods basierend auf deren Labels zuständig. Daher ist das Erste, was zu tun ist, zu überprüfen, wie viele Pods mit dem Dienst verbunden sind. Dazu können die Endpunkte im Dienst überprüft werden:
kubectl describe service | grep Endpoints Ein Endpunkt ist ein Paar von Werten in der Form <IP-адрес:порт>, und die Ausgabe sollte mindestens ein solches Paar enthalten (d.h. es arbeitet mindestens ein Pod mit dem Dienst zusammen).
Wenn der Abschnitt Endpoints leer ist, gibt es zwei Möglichkeiten:
- es gibt keinen einzigen Pod mit dem richtigen Label (Hinweis: Überprüfen Sie, ob der Namespace korrekt ausgewählt ist);
- es gibt einen Fehler in den Labels des Dienstes im Selektor.
Wenn Sie eine Liste von Endpunkten sehen, aber dennoch keinen Zugang zur Anwendung erhalten können, ist wahrscheinlich ein Fehler in der targetPort Beschreibung des Dienstes.
Wie überprüft man die Funktionsfähigkeit des Dienstes?
Unabhängig vom Servicetyp können Sie den Befehl verwenden kubectl port-forward um eine Verbindung herzustellen:
kubectl port-forward service/ 3000:80Hier:
-
<service-name>— der Name des Dienstes; - 3000 — der Port, den Sie auf Ihrem Computer öffnen;
- 80 — der Port auf der Seite des Dienstes.
3. Diagnose des Ingress
Wenn Sie bis hierher gelesen haben, dann:
- Pods werden als
RunningundBereit; - der Dienst verteilt den Verkehr erfolgreich auf die Pods.
Allerdings können Sie die Anwendung immer noch nicht erreichen.
Das bedeutet, dass der Ingress-Controller wahrscheinlich nicht richtig konfiguriert ist. Da der Ingress-Controller ein externer Bestandteil im Cluster ist, gibt es verschiedene Debugging-Methoden, abhängig von seinem Typ.
Bevor Sie jedoch spezielle Tools zur Konfiguration des Ingress verwenden, können Sie etwas ganz Einfaches tun. Ingress verwendet serviceName und servicePort um eine Verbindung zum Dienst herzustellen. Sie sollten überprüfen, ob sie korrekt konfiguriert sind. Dies kann mit dem Befehl erfolgen:
kubectl describe ingress Wenn die Spalte Backend leer ist, ist die Wahrscheinlichkeit hoch, dass ein Fehler in der Konfiguration vorliegt. Wenn die Backends vorhanden sind, aber der Zugriff auf die Anwendung weiterhin nicht möglich ist, kann das Problem mit folgender Punkte zusammenhängen:
- der Erreichbarkeit des Ingress aus dem öffentlichen Internet;
- Verfügbarkeitseinstellungen des Clusters aus dem öffentlichen Internet.
Um Probleme mit der Infrastruktur zu identifizieren, können Sie sich direkt mit dem Pod des Ingress verbinden. Suchen Sie dafür zuerst den Pod des Ingress-Controllers (er kann sich in einem anderen Namensraum befinden):
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 PortsSchließlich verbinden Sie sich mit dem Pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemJetzt werden alle Anfragen an Port 3000 auf Port 80 des Pods umgeleitet.
Funktioniert er jetzt?
- Wenn ja, liegt ein Problem mit der Infrastruktur vor. Es ist notwendig herauszufinden, wie der Datenverkehr in den Cluster geleitet wird.
- Wenn nicht, liegt ein Problem mit dem Ingress-Controller vor.
Wenn Sie den Ingress-Controller nicht zum Laufen bringen, müssen Sie ihn debuggen.
Es gibt viele Arten von Ingress-Controllern. Die beliebtesten sind Nginx, HAProxy, Traefik und andere. (mehr zu den verfügbaren Lösungen siehe — Anmerkung des Übersetzers). Sie sollten die Fehlersuche in der Dokumentation des entsprechenden Controllers verwenden. Da der populärste Ingress-Controller ist, haben wir einige Tipps zur Lösung von Problemen, die damit verbunden sind, in den Artikel aufgenommen.
Debugging des Nginx Ingress Controllers
Das Ingress-nginx-Projekt hat ein offizielles . Der Befehl kubectl ingress-nginx kann verwendet werden für:
- Analyse von Protokollen, Back-Ends, Zertifikaten usw.;
- Verbindung zu Ingress;
- Untersuchung der aktuellen Konfiguration.
Dazu helfen Ihnen die folgenden drei Befehle:
-
kubectl ingress-nginx lint— überprüftnginx.conf; -
kubectl ingress-nginx backend— erkundet das Back-End (analog zukubectl describe ingress); -
kubectl ingress-nginx logs— prüft die Protokolle.
Bitte beachten Sie: In manchen Fällen kann es erforderlich sein, den richtigen Namespace für den Ingress-Controller mit dem Flag --namespace.
Zusammenfassung
Die Diagnose in Kubernetes kann eine Herausforderung sein, wenn man nicht weiß, wo man anfangen soll. An das Problem sollte man immer von „unten nach oben“ herangehen: Beginnen Sie mit den Pods und gehen Sie dann zum Service und Ingress über. Die Debugging-Methoden, die in diesem Artikel beschrieben sind, können auch auf andere Objekte angewendet werden, wie:
- nicht funktionierende Jobs und CronJobs;
- StatefulSets und DaemonSets.
Mein Dank gilt , und für wertvolle Hinweise und Ergänzungen.
P.S. vom Übersetzer
Lesen Sie auch in unserem Blog:
- «»;
- «»;
- «»;
- «».
Quelle: habr.com
