Opmerking vertaler.: Dit artikel maakt deel uit van de openbare materialen van het project , dat is ontworpen voor zowel bedrijven als individuele beheerders om te leren werken met Kubernetes. Daniele Polencic, de projectleider, deelt er een praktische handleiding over welke stappen je kunt ondernemen bij algemene problemen met applicaties die in een K8s-cluster draaien.

TL;DR: hier is een schema dat je helpt bij het debuggen van deployments in Kubernetes:
Een stroomdiagram voor het vinden en oplossen van fouten in het cluster. In het origineel (in het Engels) is het beschikbaar op en .
Bij het implementeren van een applicatie in Kubernetes moet je meestal drie componenten definiëren:
- Deployment — dit is een soort recept voor het maken van kopieën van de applicatie, genaamd pods;
- Service — een interne load balancer die het verkeer over de pods verdeelt;
- Ingress — een beschrijving van hoe het verkeer van de buitenwereld naar de Service gaat.
Hier is een kort grafisch overzicht:
1) In Kubernetes ontvangen applicaties verkeer vanuit de buitenwereld via twee lagen load balancers: intern en extern.

2) De interne load balancer heet Service, de externe – Ingress.

3) Deployment creëert pods en houdt toezicht op hen (ze worden niet handmatig gemaakt).

Laten we aannemen dat je een eenvoudig applicatie wilt implementeren zoals Hello World. De YAML-configuratie daarvoor ziet er als volgt uit:
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: /De definitie is vrij lang en het is makkelijk om in de war te raken over hoe de componenten met elkaar verbonden zijn.
Bijvoorbeeld:
- Wanneer moet je poort 80 gebruiken en wanneer 8080?
- Moet je voor elke service een nieuwe poort aanmaken, zodat ze niet conflicteren?
- Hebben labels namenbelangrijk? Moeten ze overal hetzelfde zijn?
Voordat we ons richten op het debuggen, laten we herinneren hoe de drie componenten met elkaar zijn verbonden. Laten we beginnen met Deployment en Service.
De relatie tussen Deployment en Service
Je zult verrast zijn, maar Deployments en Services zijn helemaal niet met elkaar verbonden. In plaats daarvan wijst de Service rechtstreeks naar de pods, voorbij de Deployment.
Daarom zijn we geïnteresseerd in hoe Pods en Services met elkaar verbonden zijn. Er zijn drie dingen om te onthouden:
- De selector (
selector) van de Service moet overeenkomen met ten minste één label van de Pod. -
targetPortmoet overeenkomen metcontainerPortvan de container binnen de Pod. -
portDe poort van de Service kan willekeurig zijn. Verschillende services kunnen dezelfde poort gebruiken, omdat ze verschillende IP-adressen hebben.
Het volgende diagram geeft alles hierboven in grafische vorm weer:
1) Stel je voor dat de service verkeer naar een bepaalde pod stuurt:

2) Bij het maken van de pod moet je opgeven containerPort voor elke container in de pods:

3) Bij het aanmaken van de service moet je opgeven port en targetPort. Maar via welke gebeurt de verbinding met de container?

4) Via targetPort. Het moet overeenkomen met containerPort.

5) Stel dat de poort 3000 in de container geopend is. Dan moet de waarde targetPort hetzelfde zijn.

In het YAML-bestand moeten de labels en poorten / targetPort overeenkomen:
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 # <<< Wat is er met het label track: canary in de bovenste sectie van de Deployment? Moet het overeenkomen?
Dit label heeft betrekking op de uitrol en wordt niet door de service gebruikt voor verkeersroutering. Met andere woorden, het kan worden verwijderd of een andere waarde krijgen.
En wat dan met de selector matchLabels?
Die moet altijd overeenkomen met de labels van de Pod, omdat deze door de Deployment wordt gebruikt om de pods te volgen.
Stel je voor dat je de juiste wijzigingen hebt aangebracht. Hoe kun je deze controleren?
Je kunt de labels van de pods controleren met de volgende opdracht:
kubectl get pods --show-labelsOf, als de pods tot meerdere applicaties behoren:
kubectl get pods --selector any-name=my-app --show-labels Waarbij any-name=my-app — dit is een label any-name: my-app.
Zit je nog met vragen?
Je kunt verbinding maken met de pod! Hiervoor moet je de opdracht gebruiken port-forward in kubectl. Hiermee kun je verbinding maken met de service en de verbinding controleren.
kubectl port-forward service/ 3000:80Hier:
-
service/— de naam van de service; in ons geval is ditmy-service; - 3000 — de poort die geopend moet worden op de computer;
- 80 — de poort die is ingevoerd in het veld
portvan de service.
Als de verbinding tot stand is gebracht, zijn de instellingen correct.
Als de verbinding niet tot stand kan worden gebracht, is er waarschijnlijk een probleem met de labels of komen de poorten niet overeen.
De verbinding tussen de Service en de Ingress
De volgende stap om toegang tot de applicatie te garanderen, is het configureren van de Ingress. De Ingress moet weten hoe hij de service kan vinden, vervolgens de pods kan vinden en het verkeer naar hen kan leiden. De Ingress vindt de juiste service aan de hand van de naam en de open poort.
In de beschrijving van de Ingress en de Service moeten twee parameters overeenkomen:
-
servicePortin de Ingress moet overeenkomen met de parameterportin de Service; -
serviceNamein de Ingress moet overeenkomen met het veldnaamin de Service.
De volgende diagram geeft een samenvatting van de poortverbindingen:
1) Zoals u misschien al weet, luistert de Service naar een bepaalde port:

2) De Ingress heeft een parameter dat servicePort:

3) Deze parameter (servicePort) moet altijd overeenkomen met port in de definitie van de Service:

4) Als de Service poort 80 heeft ingesteld, moet servicePort ook gelijk zijn aan 80:

In de praktijk moet aandacht worden besteed aan de volgende regels:
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: /Hoe controleer je of de Ingress werkt?
Je kunt de methode met kubectl port-forwardgebruiken, maar in plaats van de service moet je verbinding maken met de Ingress-controller.
Eerst moet je de naam van de pod met de Ingress-controller achterhalen:
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 Zoek de Ingress-pod (deze kan tot een andere namespace behoren) en voer de opdracht uit beschrijven, om de poortnummers te achterhalen:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPVerbind ten slotte met de pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemNu, elke keer dat je een aanvraag op poort 3000 op je computer verzendt, wordt deze omgeleid naar poort 80 van de pod met de Ingress-controller. Als je naar , gaat, moet je de pagina zien die door de applicatie is gemaakt.
Samenvatting van de poorten
Laten we nogmaals kijken naar welke poorten en labels overeen moeten komen:
- De selector in de definitie van de Service moet overeenkomen met het label van de pod;
-
targetPortin de definitie van de Service moet overeenkomen metcontainerPortde container binnen de pod; -
portIn de definitie van Service kan iets zijn. Verschillende services kunnen dezelfde poort gebruiken, omdat ze verschillende IP-adressen hebben; -
servicePortIngresse moet overeenkomen metportin de definitie van Service; - De naam van de service moet overeenkomen met het veld
serviceNamein Ingress.
Helaas is het niet genoeg om te weten hoe je een YAML-configuratie correct moet structureren.
Wat gebeurt er als er iets misgaat?
Misschien wordt de pod niet gestart of crasht deze.
3 stappen voor het diagnosticeren van applicatiefouten in Kubernetes
Voordat je begint met het debuggen van de deployment, moet je een goed begrip hebben van hoe Kubernetes werkt.
Aangezien elke applicatie in K8s drie componenten heeft, moet je ze in een bepaalde volgorde debuggen, te beginnen van de onderkant.
- Eerst moet je controleren of de pods werken, dan…
- Controleren of de service verkeer naar de pods levert, en dan…
- Controleren of de Ingress correct is ingesteld.
Visuele voorstelling:
1) Problemen moeten worden opgezocht vanaf de onderkant. Controleer eerst of de pods de status hebben Klaar en Running:

2) Als de pods gereed zijn (Klaar), moet je achterhalen of de service verkeer tussen de pods verdeelt:

3) Ten slotte moet je de relatie tussen de service en de Ingress analyseren:

1. Diagnostiek van de pods
In de meeste gevallen is het probleem gerelateerd aan de pod. Zorg ervoor dat de pods worden weergegeven als Klaar en Running. Dit kun je controleren met het commando:
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 de uitvoer van het bovenstaande commando wordt de laatste pod weergegeven als Running en Klaar, maar dat is bij de andere twee niet het geval.
Hoe weet je dat er iets mis is gegaan?
Er zijn vier nuttige commando's voor het diagnosticeren van pods:
-
kubectl logslaat toe om logs uit de containers in de pod te extraheren; -
kubectl describe podlaat je een lijst van gebeurtenissen met betrekking tot de pod zien; -
kubectl get podlaat de YAML-configuratie van de pod zien, opgeslagen in Kubernetes; -
kubectl exec -ti bashmaakt het mogelijk om een interactieve commandoregel te starten in een van de containers van de pod
Welke moet je kiezen?
Het probleem is dat er niet één universeel commando is. Je moet een combinatie van hen gebruiken.
Typische problemen met pods
Er zijn twee hoofdtypen fouten bij pods: fouten tijdens het opstarten (startup) en fouten tijdens het draaien (runtime).
Opstartfouten:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
OngeldigeAfbeeldingNaam
Runtime-fouten:
-
CrashLoopBackOff -
RunContainerFout -
KillContainerFout -
ControleerNietRootFout -
RunInitContainerFout -
CreëerPodSandboxFout -
ConfigPodSandboxFout -
KillPodSandboxFout -
OpzettenNetwerkFout -
AfbrekenNetwerkFout
Sommige fouten komen vaker voor dan andere. Hier zijn enkele van de meest voorkomende fouten en manieren om ze op te lossen.
ImagePullBackOff
Deze fout verschijnt wanneer Kubernetes de afbeelding voor een van de containers in de pod niet kan ophalen. Hier zijn drie veelvoorkomende redenen hiervoor:
- De naam van de afbeelding is onjuist opgegeven - bijvoorbeeld, je hebt een fout gemaakt, of de afbeelding bestaat niet;
- Een niet-bestaande tag voor de afbeelding is opgegeven;
- De afbeelding is opgeslagen in een privé register, en Kubernetes heeft geen bevoegdheden om er toegang toe te krijgen.
De eerste twee redenen zijn gemakkelijk op te lossen - je hoeft alleen de naam van de afbeelding en de tag te corrigeren. In het geval van de laatste moet je de inloggegevens voor het privé register in Secret invoeren en verwijzingen ernaar toevoegen in de pods. In de Kubernetes-documentatie van hoe je dit kunt doen.
CrashLoopBackOff
Kubernetes geeft een fout weer CrashLoopBackOff, als de container niet kan worden gestart. Dit gebeurt meestal wanneer:
- Er een fout in de applicatie is die het starten ervan verhindert;
- Container ;
- De Liveness-test is te vaak mislukt.
Je moet proberen toegang te krijgen tot de logs van de container om de oorzaak van de crash te achterhalen. Als het moeilijk is om toegang te krijgen tot de logs omdat de container te snel opnieuw opstart, kun je de volgende opdracht gebruiken:
kubectl logs --previousDeze geeft foutmeldingen weer van de vorige incarnatie van de container.
RunContainerFout
Deze fout treedt op wanneer de container niet kan worden gestart. Dit komt overeen met het moment vóór het starten van de applicatie. Meestal is de oorzaak een verkeerde configuratie, bijvoorbeeld:
- een poging om een niet-bestaande volume te monteren, zoals ConfigMap of Secrets;
- een poging om een read-only volume als read-write te monteren.
Voor het analyseren van dergelijke fouten is de opdracht goed geschikt kubectl describe pod.
Pods in de status Pending
Na het creëren van de pod blijft deze in de status Pending.
Waarom gebeurt dit?
Hier zijn mogelijke oorzaken (ik ga ervan uit dat de scheduler normaal werkt):
- Er zijn onvoldoende middelen in de cluster, zoals rekenkracht en geheugen, om de pod te starten.
- In de overeenkomstige namespace is een object ingesteld
ResourceQuotaen het creëren van een pod zal ervoor zorgen dat de naamruimte de quota overschrijdt. - Pod is gekoppeld aan Pending
PersistentVolumeClaim.
In dit geval wordt aanbevolen om het commando te gebruiken kubectl describe en de sectie te controleren Gebeurtenissen:
kubectl describe pod <pod naam> Bij fouten gerelateerd aan ResourceQuotas, wordt aangeraden om de clusterlogs te bekijken met het commando
kubectl get events --sort-by=.metadata.creationTimestampPods zijn niet in de status Ready
Als de pod wordt vermeld als Running, maar niet in de status Klaar, betekent dit dat de gezondheidstest (readiness probe) mislukt.
Wanneer dit gebeurt, maakt de pod geen verbinding met de service en ontvangt geen verkeer. De mislukking van de readiness-test wordt vaak veroorzaakt door problemen in de applicatie. In dit geval is het noodzakelijk om de sectie te analyseren Gebeurtenissen in de uitvoer van het commando kubectl describe.
2. Diagnostiek van services
Als de pods worden vermeld als Running en Klaar, maar er geen respons van de applicatie is, moeten de service-instellingen worden gecontroleerd.
Services zijn verantwoordelijk voor het routeren van verkeer naar pods op basis van hun labels. Daarom is het eerste wat moet worden gedaan, controleren hoeveel pods met de service samenwerken. Dit kan worden gedaan door de endpoints in de service te controleren:
kubectl describe service <service-naam> | grep Endpoints Een endpoint is een paar waarden van het type <IP-adres:poort>, en de uitvoer moet ten minste één dergelijk paar bevatten (dat wil zeggen, er werkt ten minste één pod met de service).
Als de sectie Endpoints leeg is, zijn er twee mogelijkheden:
- er is geen enkele pod met het juiste label (tip: controleer of de juiste namespace is gekozen);
- er is een fout in de labels van de service in de selector.
Als je een lijst met endpoints ziet, maar nog steeds geen toegang tot de applicatie kunt krijgen, is de waarschijnlijke oorzaak een fout in targetPort de servicebeschrijving.
Hoe de werking van de service te controleren?
Ongeacht het type service, kan het command kubectl port-forward worden gebruikt om verbinding te maken:
kubectl port-forward service/<service-naam> 3000:80Hier:
-
<service-naam>— de naam van de service; - 3000 — de poort die je op je computer opent;
- 80 — de poort aan de kant van de service.
3. Diagnostiek van Ingress
Als je tot hier hebt gelezen, dan:
- de pods worden vermeld als
RunningenKlaar; - de service verdeelt het verkeer succesvol over de pods.
Echter, je kunt nog steeds niet 'bereiken' tot de applicatie.
Dit betekent dat de Ingress-controller waarschijnlijk niet goed is ingesteld. Aangezien de Ingress-controller een externe component in de cluster is, zijn er verschillende methoden voor foutopsporing, afhankelijk van het type.
Maar voordat u speciale tools voor de configuratie van Ingress wilt gebruiken, kunt u iets heel eenvoudigs doen. Ingress gebruikt serviceName en servicePort voor het verbinden met de service. Het is noodzakelijk om te controleren of ze goed zijn ingesteld. Dit kan met het commando:
kubectl describe ingress Als de kolom Backend leeg is, is de kans op een configuratiefout groot. Als de backends aanwezig zijn, maar toegang tot de applicatie nog steeds ontbreekt, kan het probleem liggen aan:
- de beschikbaarheidsinstellingen van de Ingress vanuit het publieke internet;
- de beschikbaarheidsinstellingen van het cluster vanuit het publieke internet.
Problemen met de infrastructuur kunnen worden vastgesteld door rechtstreeks verbinding te maken met de pod van de Ingress. Zoek eerst de pod van de Ingress-controller (deze kan zich in een andere namespace bevinden):
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 Gebruik het commando beschrijven, om de poort in te stellen:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep PortsVerbind ten slotte met de pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemNu worden alle verzoeken op poort 3000 op uw computer omgeleid naar poort 80 van de pod.
Werkt het nu?
- Als dat zo is, ligt het probleem bij de infrastructuur. Het is noodzakelijk om te achterhalen hoe het verkeer precies naar het cluster wordt gerouteerd.
- Als dat niet zo is, ligt het probleem bij de Ingress-controller.
Als het niet lukt om de Ingress-controller aan de praat te krijgen, moet u deze debuggen.
Er zijn veel varianten van Ingress-controllers. De populairste zijn Nginx, HAProxy, Traefik en meer. (meer over bestaande oplossingen in – opmerking vert.) Raadpleeg de documentatie van de betreffende controller voor het oplossen van problemen. Aangezien de populairste Ingress-controller is, hebben we enkele tips voor het oplossen van problemen met deze controller in het artikel opgenomen.
Debugging de Ingress Nginx-controller
Het Ingress-nginx-project heeft een officiële . Het commando kubectl ingress-nginx kan worden gebruikt voor:
- het analyseren van logs, backends, certificaten, enz.;
- verbinding maken met de Ingress;
- de huidige configuratie bekijken.
De volgende drie commando's kunnen u daarbij helpen:
-
kubectl ingress-nginx lint— controleertnginx.conf; -
kubectl ingress-nginx backend— onderzoekt de backend (vergelijkbaar metkubectl describe ingress); -
kubectl ingress-nginx logs— controleert logs.
Houd er rekening mee dat in sommige gevallen het nodig kan zijn om de juiste namespace voor de Ingress-controller op te geven met de vlag --namespace.
Samenvatting
Diagnose in Kubernetes kan een uitdagende taak zijn als je niet weet waar te beginnen. Het probleem moet altijd vanuit een 'bottom-up'-benadering worden aangepakt: begin met pods en ga vervolgens verder naar services en Ingress. De debugmethoden die in het artikel worden beschreven, kunnen ook op andere objecten worden toegepast, zoals:
- niet-functionerende Jobs en CronJobs;
- StatefulSets en DaemonSets.
Ik wil mijn dank uitspreken , en voor waardevolle opmerkingen en aanvullingen.
P.S. van de vertaler
Lees ook op onze blog:
- «»;
- «»;
- «»;
- «».
Bron: habr.com
