Anmerkung des Übersetzers.: Dieser Artikel ist Teil der im Rahmen des Projekts veröffentlichten Materialien, die öffentlich zugänglich sind. , die Administratoren von Unternehmen und Einzelpersonen im Umgang mit Kubernetes schulen. Darin teilt Daniele Polencic, der Projektleiter, eine anschauliche Anleitung darüber, welche Schritte bei allgemeinen Problemen mit Anwendungen, die in einem K8s-Cluster laufen, unternommen werden sollten.

TL;DR: Hier ist ein Schema, das Ihnen hilft, das Deployment in Kubernetes zu debuggen:
Flussdiagramm zur Fehlersuche und Fehlerbehebung im Cluster. Im Original (auf Englisch) ist es verfügbar in und .
Bei der Bereitstellung einer Anwendung in Kubernetes müssen in der Regel drei Komponenten definiert werden:
- Deployment — dies ist ein Rezept zur Erstellung von Anwendungen, die als Pods bezeichnet werden;
- Service — ein interner Lastenausgleich, der den Verkehr auf die Pods verteilt;
- Ingress — eine Beschreibung, wie der Verkehr aus der Außenwelt zum Service gelangt.
Hier ist eine kurze grafische Zusammenfassung:
1) In Kubernetes erhalten Anwendungen über zwei Schichten von Lastenausgleichern Verkehr aus der Außenwelt: intern und extern.

2) Der interne Lastenausgleich wird Service genannt, der externe – Ingress.

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

Angenommen, Sie möchten eine einfache Anwendung wie Hello World. 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 kann leicht passieren, dass man verwirrt wird, wie die Komponenten miteinander verbunden sind.
Zum Beispiel:
- Wann sollte man Port 80 verwenden und wann 8080?
- Sollte für jeden Dienst ein neuer Port erstellt werden, um Konflikte zu vermeiden?
- Haben die Namen der Labels eine Bedeutung? Müssen sie überall gleich sein?
Bevor wir uns auf die Fehlersuche konzentrieren, lassen Sie uns daran erinnern, wie die drei Komponenten miteinander verbunden sind. Lassen Sie uns mit Deployment und Service beginnen.
Die Verbindung zwischen Deployment und Service
Sie werden überrascht sein, aber Deployments und Services sind nicht miteinander verbunden. Stattdessen verweist der Service direkt auf Pods, um das Deployment zu umgehen.
Daher interessiert uns, wie Pods und Services miteinander verbunden sind. Man sollte sich an drei Dinge erinnern:
- Der Selektor (
selector) eines Services muss mindestens einem Label des Pods entsprechen. -
targetPortmuss übereinstimmen mitcontainerPortdes Containers innerhalb des Pods. -
portDie Service-Ports können beliebig sein. Verschiedene Services können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben.
Das folgende Diagramm stellt alles oben Genannte grafisch dar:
1) Angenommen, der Service leitet den Datenverkehr an einen bestimmten Pod weiter:

2) Bei der Erstellung eines Pods muss man Folgendes angeben containerPort für jeden Container in den Pods:

3) Bei der Erstellung eines Services muss man Folgendes angeben port und targetPort. Aber über welchen erfolgt die Verbindung zum Container?

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

5) Angenommen, im Container ist der Port 3000 geöffnet. Dann sollte der Wert targetPort derselbe 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 mit dem Label track: canary im oberen Teil des Deployment-Bereichs? Muss es übereinstimmen?
Dieses Label gehört zum Deployment und wird vom Service nicht zur Verkehrslenkung verwendet. Mit anderen Worten, es kann entfernt oder anderswertig zugewiesen werden.
Und wie steht es mit dem Selektor matchLabels?
Er muss immer mit den Labels des Pods übereinstimmen, da er vom Deployment verwendet wird, um Pods zu verfolgen.
Angenommen, Sie haben die richtigen Änderungen vorgenommen. Wie können Sie diese überprüfen?
Die Labels der Pods kann man mit dem folgenden Befehl überprüfen:
kubectl get pods --show-labelsOder, wenn die Pods zu mehreren Anwendungen gehören:
kubectl get pods --selector any-name=my-app --show-labels Wo any-name=my-app — das ist das Label any-name: my-app.
Gibt es noch Unklarheiten?
Sie können sich mit dem Pod verbinden! Dazu verwenden Sie den Befehl port-forward in kubectl. Dieser ermöglicht es Ihnen, sich mit dem Service zu verbinden und die Verbindung zu überprüfen.
kubectl port-forward service/<service name> 3000:80Hier:
-
service/<service name>— der Name des Services; in unserem Fall ist dasmy-service; - 3000 — der Port, der auf dem Computer geöffnet werden muss;
- 80 — der im Feld angegebene Port
portfür den Dienst.
Wenn die Verbindung erfolgreich hergestellt wurde, sind die Einstellungen korrekt.
Wenn die Verbindung nicht hergestellt werden konnte, liegt wahrscheinlich ein Problem mit den Labels oder den Ports vor.
Verbindung zwischen Service und Ingress
Der nächste Schritt zur Gewährleistung des Zugriffs auf die Anwendung besteht in der Konfiguration des Ingress. Der Ingress muss wissen, wie er den Service finden kann, um dann die Pods zu finden und den Verkehr dorthin zu leiten. Der Ingress findet den entsprechenden Service anhand des Namens und des offenen Ports.
In der Beschreibung müssen zwei Parameter zwischen Ingress und Service übereinstimmen:
-
servicePortim Ingress muss mit dem Parameter übereinstimmenportim Service; -
serviceNameim Ingress muss mit dem Feld übereinstimmennameim Service.
Das folgende Schema fasst die Anschlussports zusammen:
1) Wie Sie bereits wissen, hört der Service auf einen bestimmten port:

2) Der Ingress hat einen Parameter, der als servicePort:

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

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

In der Praxis sollten Sie auf die folgenden Zeilen achten:
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.
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 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 Traffic, den Sie an Port 3000 auf Ihrem Computer senden, an den Port 80 des Pods mit dem Ingress-Controller weitergeleitet. Wenn Sie auf , sollten Sie die von der Anwendung generierte Seite sehen.
Zusammenfassung der Ports
Lassen Sie uns noch einmal darauf zurückkommen, welche Ports und Labels übereinstimmen müssen:
- Der Selector in der Definition des Services muss mit dem Label des Pods übereinstimmen;
-
targetPortin der Definition des Services muss mitcontainerPortdes Containers innerhalb des Pods übereinstimmen; -
portIm Dienst ist es beliebig. Verschiedene Dienste können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben; -
servicePortIngress muss übereinstimmen mitportder Definition des Dienstes; - Der Name des Dienstes 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?
Möglicherweise startet der Pod nicht oder er stürzt ab.
3 Schritte zur Fehlersuche in Anwendungen in Kubernetes
Bevor Sie mit der Fehlersuche beim Deployment beginnen, sollten Sie ein gutes Verständnis dafür haben, wie Kubernetes funktioniert.
Da jede in K8s bereitgestellte Anwendung drei Komponenten hat, sollten Sie diese in einer bestimmten Reihenfolge debuggen, beginnend von unten.
- Zuerst müssen Sie sicherstellen, dass die Pods laufen, dann…
- Überprüfen, ob der Dienst Verkehr zu den Pods liefert, und dann…
- Überprüfen, ob der Ingress richtig konfiguriert ist.
Visuelle Darstellung:
1) Bei der Problemlösung sollte mit dem Untersten begonnen werden. Überprüfen Sie zunächst, ob die Pods den Status haben Bereit und Laufend:

2) Wenn die Pods bereit sind (Bereit), sollte geprüft werden, ob der Dienst den Verkehr zwischen den Pods verteilt:

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

1. Fehlersuche bei Pods
In den meisten Fällen liegt das Problem am Pod. Stellen Sie sicher, dass die Pods als Bereit und Laufendaufgelistet sind. Dies kann mit dem Befehl überprüft werden:
kubectl get pods
NAME READY STATUS RESTARTS AGE
app1 0/1 ImagePullBackOff 0 47h
app2 0/1 Fehler 0 47h
app3-76f9fcd46b-xbv4k 1/1 Läuft 1 47h Im obigen Ausgabe wird der letzte Pod als Laufend und Bereitangezeigt, jedoch ist das bei den beiden anderen nicht der Fall.
Wie erkennt man, dass etwas schiefgelaufen ist?
Es gibt vier nützliche Befehle zur Fehlersuche bei Pods:
-
kubectl logsermöglicht das Abrufen von Protokollen aus Containern im Pod; -
kubectl describe podermöglicht das Anzeigen 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
Welchen soll man wählen?
Das Ding ist, dass es keinen universellen Befehl gibt. Man sollte eine Kombination von ihnen verwenden.
Typische Probleme mit Pods
Es gibt zwei Haupttypen von Pod-Fehlern: Startfehler und Laufze fehler.
Startfehler:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
UngültigerBildname
Laufzeitfehler:
-
CrashLoopBackOff -
RunContainerFehler -
KillContainerFehler -
VerifyNonRootFehler -
RunInitContainerFehler -
CreatePodSandboxFehler -
ConfigPodSandboxFehler -
KillPodSandboxFehler -
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 das Image für einen der Container des Pods nicht abrufen kann. Hier sind drei der häufigsten Gründe dafür:
Der Name des Images ist falsch angegeben — zum Beispiel haben Sie einen Fehler gemacht oder das Image existiert nicht;
Ein nicht vorhandenes Tag für das Image wurde angegeben;
- Das Image wird in einem privaten Registry gespeichert, und Kubernetes hat keine Berechtigung, darauf zuzugreifen.
- Die ersten beiden Ursachen sind einfach zu beheben — man muss nur den Namen des Images und das Tag korrigieren. Im letzten Fall müssen die Zugangsdaten für das private Registry in ein Secret eingefügt und diese in die Pods aufgenommen werden. In der Kubernetes-Dokumentation
- gibt es ein Beispiel
dafür, wie man das machen kann. , wenn der Container nicht starten kann. Dies geschieht normalerweise, wenn:
CrashLoopBackOff
Es einen Fehler in der Anwendung gibt, der den Start verhindert; CrashLoopBackOffnicht richtig konfiguriert ist
- Der Liveness-Test ist zu oft fehlgeschlagen.
- Container ;
- kubectl logs --previous
Er gibt Fehlermeldungen aus der vorherigen Inkarnation des Containers aus.
Dieser Fehler tritt auf, wenn der Container nicht in der Lage ist, zu starten. Er entspricht dem Zeitpunkt vor dem Start der Anwendung. Üblicherweise ist die Ursache eine falsche Konfiguration, zum Beispiel:das Versuchen, ein nicht vorhandenes Volume wie ConfigMap oder Secrets zu mounten;
RunContainerFehler
das Versuchen, ein Read-Only-Volume als Read-Write zu mounten.
- Zur Analyse solcher Fehler eignet sich der Befehl
- kubectl describe pod
Pods im Zustand Pending Nach der Erstellung bleibt der Pod im Zustand.
Warum passiert das?
Hier sind mögliche Gründe (ich gehe davon aus, dass der Scheduler normal funktioniert): Pending.
Im Cluster fehlen Ressourcen, wie CPU und RAM, um den Pod zu starten.
Im entsprechenden Namensraum ist ein Objekt
- ResourceQuota
- Im entsprechenden Namensraum wurde ein Objekt festgelegt
ResourceQuotaDie Erstellung des Pods führt dazu, dass der Namespace die Quote überschreitet. - Pod ist auf "Pending"
PersistentVolumeClaim.
In diesem Fall wird empfohlen, den Befehl zu verwenden kubectl describe und den Abschnitt zu überprüfen Ereignisse:
kubectl describe pod Bei Fehlern, die mit ResourceQuotasin Verbindung stehen, wird empfohlen, die Clusterprotokolle mit dem Befehl zu überprüfen
kubectl get events --sort-by=.metadata.creationTimestampPods sind nicht im "Ready"-Zustand
Wenn der Pod als Laufendgeführt wird, jedoch nicht im Bereit-Zustand ist, bedeutet das, dass die Prüfung seiner Bereitstellung (Readiness Probe) fehlgeschlagen ist.
Wenn dies der Fall ist, wird der Pod nicht mit dem Dienst verbunden und erhält keinen Verkehr. Der Fehler bei der Readiness-Prüfung wird durch Probleme in der Anwendung verursacht. In diesem Fall sollten Sie den Abschnitt analysieren Ereignisse in der Ausgabe des Befehls kubectl describe.
2. Diagnostik von Diensten
Wenn Pods als Laufend und Bereitangezeigt werden, aber weiterhin keine Antwort von der Anwendung kommt, sollten die Diensteinstellungen überprüft werden.
Dienste routen den Verkehr zu Pods basierend auf deren Labels. Daher sollten Sie als erstes überprüfen, wie viele Pods mit dem Dienst aktiv sind. Dazu können Sie die Endpunkte im Dienst überprüfen:
kubectl describe service | grep Endpoints Ein Endpoint ist ein Paar von Werten in der Form <IP-адрес:порт>und es sollte mindestens ein solches Paar in der Ausgabe vorhanden sein (d.h. es arbeitet mindestens ein Pod mit dem Dienst).
Wenn der Abschnitt Endpoints leer ist, gibt es zwei Möglichkeiten:
- Es gibt keinen Pod mit dem richtigen Label (Hinweis: Überprüfen Sie, ob der Namespace korrekt ausgewählt ist);
- Es liegt ein Fehler in den Labels des Dienstes im Selektor vor.
Wenn Sie eine Liste von Endpunkten sehen, aber weiterhin keinen Zugriff auf die Anwendung haben, ist wahrscheinlich ein Fehler in targetPort der Beschreibung des Dienstes.
Wie überprüft man die Funktionsfähigkeit des Dienstes?
Unabhängig von der Art des Dienstes können Sie den Befehl verwenden kubectl port-forward um sich mit ihm zu verbinden:
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 Dienstseite.
3. Diagnostik von Ingress
Wenn Sie bis hierher gelesen haben, dann:
- Pods sind als
LaufendundBereit; - angezeigt, der Dienst verteilt den Verkehr erfolgreich auf die Pods.
Sie können jedoch weiterhin nicht auf die Anwendung zugreifen.
Das bedeutet, dass wahrscheinlich der Ingress-Controller falsch konfiguriert ist. Da der Ingress-Controller ein externes Element im Cluster ist, gibt es je nach Typ verschiedene Debugging-Methoden.
Bevor Sie jedoch auf spezielle Tools zur Konfiguration von Ingress zurückgreifen, können Sie etwas ganz Einfaches tun. Ingress verwendet serviceName und servicePort um sich mit dem Dienst zu verbinden. Sie sollten überprüfen, ob sie korrekt konfiguriert sind. Dies kann mit dem Befehl erfolgen:
kubectl describe ingress Wenn die Spalte Backend leer ist, besteht eine hohe Wahrscheinlichkeit für einen Fehler in der Konfiguration. Wenn die Backends vorhanden sind, aber der Zugriff auf die Anwendung weiterhin fehlt, könnte das Problem mit folgendem zusammenhängen:
- den Verfügbarkeitseinstellungen von Ingress aus dem öffentlichen Internet;
- den Verfügbarkeitseinstellungen des Clusters aus dem öffentlichen Internet.
Probleme mit der Infrastruktur können erkannt werden, indem Sie sich direkt mit dem Pod von Ingress verbinden. Suchen Sie zunächst 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 dem Computer an Port 80 des Pods umgeleitet.
Funktioniert er jetzt?
- Wenn ja, liegt ein Problem mit der Infrastruktur vor. Sie sollten herausfinden, wie der Verkehr im Cluster weitergeleitet wird.
- Wenn nicht, gibt es ein Problem mit dem Ingress-Controller.
Wenn der Ingress-Controller nicht funktioniert, muss er debuggt werden.
Es gibt viele Arten von Ingress-Controllern. Die beliebtesten sind Nginx, HAProxy, Traefik usw. (für weitere Informationen über bestehende Lösungen siehe — Anm. d. Übersetzer) Sie sollten das Troubleshooting-Handbuch in der Dokumentation des jeweiligen Controllers verwenden. Da der beliebteste Ingress-Controller ist, haben wir einige Tipps zur Behebung damit verbundener Probleme in den Artikel aufgenommen.
Debugging des Ingress Nginx Controllers
Das Projekt Ingress-nginx hat ein offizielles . Der Befehl kubectl ingress-nginx kann verwendet werden für:
- Analyse von Logs, Backends, Zertifikaten usw.;
- Verbindung zu Ingress;
- Anzeige der aktuellen Konfiguration.
Die folgenden drei Befehle helfen Ihnen dabei:
-
kubectl ingress-nginx lint— überprüftnginx.conf; -
kubectl ingress-nginx backend— untersucht das Backend (analog zukubectl describe ingress); -
kubectl ingress-nginx logs— überprüft die Logs.
Bitte beachten Sie: In einigen Fällen kann es erforderlich sein, den richtigen Namensraum für den Ingress-Controller mit dem Flag --namespace.
Zusammenfassung
Die Diagnose in Kubernetes kann zu einer anspruchsvollen Aufgabe werden, wenn man nicht weiß, wo man anfangen soll. Man sollte das Problem immer nach dem Prinzip „von unten nach oben“ angehen: Beginnen Sie mit den Pods und wechseln Sie dann zum Service und Ingress. Die in diesem Artikel beschriebenen Debugging-Methoden können auch auf andere Objekte angewendet werden, wie zum Beispiel:
- nicht funktionierende Jobs und CronJobs;
- StatefulSets und DaemonSets.
Ich danke , und für wertvolle Anmerkungen und Ergänzungen.
P.S. vom Übersetzer
Lesen Sie auch in unserem Blog:
- «»;
- «»;
- «»;
- «».
Quelle: habr.com
