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:
- Ein Service-
selector
muss mit mindestens einem Pod-Etikett übereinstimmen. targetPort
muss mit dem containerPort
Containers im Pod übereinstimmen.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:
servicePort
in Ingress muss mit dem servicePort
in Service übereinstimmen.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:
- Der Selektor in der Service-Definition muss mit der Pod-Bezeichnung übereinstimmen.
targetPort
in der Service-Definition muss mit dem containerPort
Containers im Pod übereinstimmen.port
in der Definition von Service kann alles sein. Verschiedene Dienste können denselben Port verwenden, da sie unterschiedliche IP-Adressen haben.servicePort
Ingress muss mit dem port
in der Service-Definition übereinstimmen.- 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.
- Zuerst müssen Sie sicherstellen, dass die Pods funktionieren, dann ...
- Überprüfen Sie, ob der Service Datenverkehr an die Pods liefert, und führen Sie dann Folgendes aus:
- Ü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:
kubectl logs < pod'>
können Sie Protokolle aus Containern in pod extrahieren.kubectl describe pod < pod'>
können Sie eine Liste der mit dem Pod verbundenen Ereignisse anzeigen.kubectl get pod < pod'>
können Sie die YAML-Konfiguration des in Kubernetes gespeicherten kubectl get pod < pod'>
abrufen.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:
- Der Bildname wurde falsch angegeben. Sie haben beispielsweise einen Fehler gemacht oder das Bild ist nicht vorhanden.
- Es wurde ein nicht vorhandenes Tag für das Bild angegeben.
- 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:
- In der Anwendung ist ein Fehler aufgetreten, der den Start verhindert.
- Der Container ist falsch konfiguriert .
- 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):
- Der Cluster verfügt nicht über genügend Ressourcen, z. B. Prozessorleistung und Arbeitsspeicher, um den Pod auszuführen.
- Das
ResourceQuota
Objekt wird im entsprechenden Namespace installiert, und das Erstellen eines Pods führt dazu, dass der Namespace das Kontingent überschreitet. - 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:
- Es gibt keine Pods mit der richtigen Bezeichnung (Hinweis: Überprüfen Sie, ob der Namespace richtig ausgewählt ist).
- 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: