Een visuele gids voor het oplossen van problemen met Kubernetes

Opmerking. vert.: Dit artikel maakt deel uit van het projectmateriaal dat in het publieke domein is gepubliceerd leer8s, het opleiden van bedrijven en individuele beheerders om met Kubernetes te werken. Daarin deelt Daniele Polencic, projectmanager, visuele instructies over welke stappen te nemen in geval van algemene problemen met applicaties die op het K8s-cluster draaien.

Een visuele gids voor het oplossen van problemen met Kubernetes

TL;DR: hier is een diagram dat u zal helpen bij het debuggen van de implementatie in Kubernetes:

Een visuele gids voor het oplossen van problemen met Kubernetes

Stroomdiagram voor het vinden en oplossen van fouten in een cluster. Het origineel (in het Engels) is beschikbaar op PDF и zoals de afbeelding.

Wanneer u een applicatie in Kubernetes implementeert, zijn er doorgaans drie componenten die u moet definiëren:

  • Deployment - dit is een soort recept voor het maken van kopieën van de applicatie, genaamd pods;
  • Service — interne load balancer die verkeer over pods verdeelt;
  • Ingress — een beschrijving van hoe het verkeer van de buitenwereld naar de Dienst zal gaan.

Hier is een korte grafische samenvatting:

1) In Kubernetes ontvangen applicaties verkeer van de buitenwereld via twee lagen load balancers: intern en extern.

Een visuele gids voor het oplossen van problemen met Kubernetes

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

Een visuele gids voor het oplossen van problemen met Kubernetes

3) Deployment maakt pods en bewaakt deze (ze worden niet handmatig gemaakt).

Een visuele gids voor het oplossen van problemen met Kubernetes

Stel dat u een eenvoudige applicatie a la wilt implementeren Hallo Wereld. De YAML-configuratie ervoor 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 gemakkelijk om in de war te raken over hoe de componenten zich tot elkaar verhouden.

Bijvoorbeeld:

  • Wanneer moet u poort 80 gebruiken en wanneer moet u 8080 gebruiken?
  • Moet ik voor elke service een nieuwe poort maken, zodat er geen conflict ontstaat?
  • Zijn labelnamen belangrijk? Moeten ze overal hetzelfde zijn?

Laten we, voordat we ons concentreren op het opsporen van fouten, onthouden hoe de drie componenten zich tot elkaar verhouden. Laten we beginnen met implementatie en service.

Relatie tussen implementatie en service

Het zal je verbazen, maar Deployment en Service zijn op geen enkele manier met elkaar verbonden. In plaats daarvan verwijst Service rechtstreeks naar Pods, waarbij de implementatie wordt omzeild.

We zijn dus geïnteresseerd in hoe Pods en Services met elkaar verband houden. Drie dingen om te onthouden:

  1. Keuzeschakelaar (selector) voor Service moet overeenkomen met ten minste één Pod-label.
  2. targetPort moet overeenkomen containerPort container in de Pod.
  3. port Dienstverlening kan van alles zijn. Verschillende services kunnen dezelfde poort gebruiken omdat ze verschillende IP-adressen hebben.

Het volgende diagram geeft al het bovenstaande in grafische vorm weer:

1) Stel je voor dat de service verkeer naar een bepaalde pod leidt:

Een visuele gids voor het oplossen van problemen met Kubernetes

2) Wanneer u een pod maakt, moet u dit opgeven containerPort voor elke container in peulen:

Een visuele gids voor het oplossen van problemen met Kubernetes

3) Wanneer u een dienst aanmaakt, moet u dit opgeven port и targetPort. Maar welke wordt gebruikt om verbinding te maken met de container?

Een visuele gids voor het oplossen van problemen met Kubernetes

4) Via targetPort. Het moet overeenkomen containerPort.

Een visuele gids voor het oplossen van problemen met Kubernetes

5) Stel dat poort 3000 open is in de container, dan de waarde targetPort zou hetzelfde moeten zijn.

Een visuele gids voor het oplossen van problemen met Kubernetes

In het YAML-bestand worden labels en ports / targetPort moet 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  # <<<

Hoe zit het met het etiket track: canary bovenaan het gedeelte Implementatie? Moet het overeenkomen?

Dit label is implementatiespecifiek en wordt niet door de service gebruikt om verkeer te routeren. Met andere woorden, het kan worden verwijderd of een andere waarde worden toegewezen.

Hoe zit het met de keuzeschakelaar matchLabels?

Het moet altijd overeenkomen met de labels van de Pod, omdat het door Deployment wordt gebruikt om pods te volgen.

Laten we aannemen dat u de juiste wijzigingen heeft aangebracht. Hoe kunt u ze controleren?

U kunt het podlabel controleren met de volgende opdracht:

kubectl get pods --show-labels

Of, als pods tot meerdere toepassingen behoren:

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

Где any-name=my-app is een etiket any-name: my-app.

Zijn er nog moeilijkheden?

U kunt verbinding maken met de pod! Om dit te doen, moet je de opdracht gebruiken port-forward in kubectl. Hiermee kunt u verbinding maken met de dienst en de verbinding controleren.

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

Здесь:

  • service/<service name> — dienstnaam; in ons geval wel my-service;
  • 3000 is de poort die op de computer moet worden geopend;
  • 80 - poort gespecificeerd in het veld port dienst.

Als de verbinding tot stand is gebracht, zijn de instellingen correct.

Als de verbinding mislukt, is er een probleem met de labels of komen de poorten niet overeen.

Relatie tussen Service en Ingress

De volgende stap bij het verlenen van toegang tot de applicatie is het instellen van Ingress. Ingress moet weten hoe hij een dienst kan vinden, vervolgens pods kan vinden en er verkeer naartoe kan leiden. Ingress vindt de vereiste service op naam en open poort.

In de beschrijving van Ingress en Service moeten twee parameters overeenkomen:

  1. servicePort in Ingress moet overeenkomen met de parameter port in dienst;
  2. serviceName in Ingress moet overeenkomen met het veld name in dienst.

Het volgende diagram vat de poortverbindingen samen:

1) Zoals je al weet, luistert Service naar een bepaald type port:

Een visuele gids voor het oplossen van problemen met Kubernetes

2) Ingress heeft een parameter genaamd servicePort:

Een visuele gids voor het oplossen van problemen met Kubernetes

3) Deze parameter (servicePort) moet altijd overeenkomen port in de Servicedefinitie:

Een visuele gids voor het oplossen van problemen met Kubernetes

4) Als poort 80 is opgegeven in Service, is dat noodzakelijk servicePort was ook gelijk aan 80:

Een visuele gids voor het oplossen van problemen met Kubernetes

In de praktijk moet u op de volgende regels letten:

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 ik of Ingress actief is?

Je kunt de methode gebruiken met kubectl port-forward, maar in plaats van de service moet u 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 bevindt zich mogelijk in een andere naamruimte) en voer de opdracht uit describeom de poortnummers te achterhalen:

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

Maak ten slotte verbinding met de pod:

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

Elke keer dat u nu een verzoek naar poort 3000 op uw computer verzendt, wordt dit doorgestuurd naar poort 80 van de pod met de Ingress-controller. Door naar http://localhost:3000, zou u de pagina moeten zien die door de toepassing is gegenereerd.

Samenvatting van havens

Laten we nogmaals onthouden welke poorten en labels moeten overeenkomen:

  1. De selector in de Servicedefinitie moet overeenkomen met het label van de pod;
  2. targetPort in de definitie Service moet overeenkomen containerPort container in een pod;
  3. port in de definitie kan service van alles zijn. Verschillende diensten kunnen dezelfde poort gebruiken omdat ze verschillende IP-adressen hebben;
  4. servicePort Ingress moet overeenkomen port in de definitie van Dienst;
  5. De servicenaam moet overeenkomen met het veld serviceName in Ingress.

Helaas is het niet voldoende om te weten hoe u een YAML-configuratie correct structureert.

Wat gebeurt er als er iets misgaat?

De pod start mogelijk niet of crasht.

3 stappen om applicatieproblemen in Kubernetes te diagnosticeren

Voordat u begint met het debuggen van uw implementatie, moet u goed begrijpen hoe Kubernetes werkt.

Omdat elke applicatie die in K8s wordt gedownload drie componenten heeft, moeten deze in een bepaalde volgorde worden gedebugd, beginnend vanaf de onderkant.

  1. Eerst moet je zeker weten dat de pods werken, en dan...
  2. Controleer of de dienst verkeer naar de pods levert, en dan...
  3. Controleer of Ingress correct is geconfigureerd.

Visuele weergave:

1) Je moet problemen vanaf de basis gaan zoeken. Controleer eerst of pods statussen hebben Ready и Running:

Een visuele gids voor het oplossen van problemen met Kubernetes

2) Als de peulen klaar zijn (Ready), moet u weten of de service verkeer tussen pods verdeelt:

Een visuele gids voor het oplossen van problemen met Kubernetes

3) Ten slotte moet u de verbinding tussen de service en de Ingress analyseren:

Een visuele gids voor het oplossen van problemen met Kubernetes

1. Diagnostiek van peulen

In de meeste gevallen heeft het probleem te maken met de pod. Zorg ervoor dat pods worden vermeld als Ready и Running. Je kunt dit 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 bovenstaande opdrachtuitvoer wordt de laatste pod weergegeven als Running и ReadyVoor de andere twee is dit echter niet het geval.

Hoe te begrijpen wat er mis is gegaan?

Er zijn vier handige opdrachten voor het diagnosticeren van pods:

  1. kubectl logs <имя pod'а> stelt u in staat logboeken uit containers in een pod te extraheren;
  2. kubectl describe pod <имя pod'а> stelt u in staat een lijst met gebeurtenissen te bekijken die aan de pod zijn gekoppeld;
  3. kubectl get pod <имя pod'а> stelt u in staat de YAML-configuratie op te halen van een pod die is opgeslagen in Kubernetes;
  4. kubectl exec -ti <имя pod'а> bash Hiermee kunt u een interactieve opdrachtshell starten in een van de podcontainers

Welke moet je kiezen?

Feit is dat er geen universeel gebod bestaat. Er moet een combinatie hiervan worden gebruikt.

Typische pod-problemen

Er zijn twee hoofdtypen pod-fouten: opstartfouten en runtime-fouten.

Opstartfouten:

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

Runtime-fouten:

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

Sommige fouten komen vaker voor dan andere. Hier volgen enkele van de meest voorkomende fouten en hoe u deze kunt oplossen.

ImagePullBackOff

Deze fout treedt op wanneer Kubernetes geen afbeelding kan verkrijgen voor een van de podcontainers. Hier zijn de drie meest voorkomende redenen hiervoor:

  1. De naam van de afbeelding is onjuist. U hebt er bijvoorbeeld een fout in gemaakt of de afbeelding bestaat niet;
  2. Er is een niet-bestaande tag opgegeven voor de afbeelding;
  3. De afbeelding wordt opgeslagen in een privéregister en Kubernetes heeft geen toegangsrechten.

De eerste twee redenen zijn eenvoudig te elimineren: corrigeer gewoon de afbeeldingsnaam en tag. In het laatste geval moet u de inloggegevens voor het gesloten register in Secret invoeren en er koppelingen naar toevoegen in pods. In de Kubernetes-documentatie er is een voorbeeld hoe dit gedaan kan worden.

Crashlus terug uit

Kubenetes genereert een fout CrashLoopBackOff, als de container niet kan starten. Dit gebeurt meestal wanneer:

  1. Er zit een bug in de applicatie waardoor deze niet kan starten;
  2. Bak verkeerd geconfigureerd;
  3. De Liveness-test is te vaak mislukt.

U moet proberen de logboeken van de container te openen om de reden voor het mislukken ervan te achterhalen. Als het moeilijk is om toegang te krijgen tot de logboeken omdat de container te snel opnieuw opstart, kunt u de volgende opdracht gebruiken:

kubectl logs <pod-name> --previous

Het geeft foutmeldingen weer van de vorige incarnatie van de container.

RunContainerError

Deze fout treedt op wanneer de container niet start. Het komt overeen met het moment voordat de applicatie wordt gestart. Het wordt meestal veroorzaakt door onjuiste instellingen, bijvoorbeeld:

  • proberen een niet-bestaand volume zoals ConfigMap of Secrets te koppelen;
  • een poging om een ​​alleen-lezen volume te koppelen als lezen-schrijven.

Het team is zeer geschikt voor het analyseren van dergelijke fouten kubectl describe pod <pod-name>.

Pods hebben de status In behandeling

Eenmaal gemaakt, blijft de pod in de staat Pending.

Waarom gebeurt dit?

Hier zijn de mogelijke redenen (ik neem aan dat de planner goed werkt):

  1. Het cluster beschikt niet over voldoende bronnen, zoals verwerkingskracht en geheugen, om de pod uit te voeren.
  2. Het object wordt in de juiste naamruimte geïnstalleerd ResourceQuota en als u een pod maakt, zal de naamruimte het quotum overschrijden.
  3. Pod is gebonden aan In behandeling PersistentVolumeClaim.

In dit geval wordt aanbevolen om de opdracht te gebruiken kubectl describe en controleer het gedeelte Events:

kubectl describe pod <pod name>

In geval van fouten met betrekking tot ResourceQuotas, wordt aanbevolen om de clusterlogboeken te bekijken met behulp van de opdracht

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

Pods zijn niet gereed

Als pod wordt vermeld als Running, maar bevindt zich niet in een staat Ready, betekent dat de gereedheid wordt gecontroleerd (gereedheidssonde) mislukt.

Wanneer dit gebeurt, maakt de pod geen verbinding met de dienst en stroomt er geen verkeer naartoe. Het mislukken van de gereedheidstest wordt veroorzaakt door problemen in de applicatie. In dit geval moet u de sectie analyseren om de fout te vinden Events in de opdrachtuitvoer kubectl describe.

2. Servicediagnostiek

Als pods worden vermeld als Running и Ready, maar er is nog steeds geen reactie van de applicatie, u moet de service-instellingen controleren.

Services zijn verantwoordelijk voor het routeren van verkeer naar pods, afhankelijk van hun labels. Daarom moet u eerst controleren hoeveel pods met de service werken. Om dit te doen, kunt u de eindpunten in de service controleren:

kubectl describe service <service-name> | grep Endpoints

Eindpunt is een paar waarden van het formulier <IP-адрес:порт>, en minstens één zo'n paar moet aanwezig zijn in de uitvoer (dat wil zeggen, minstens één pod werkt met de service).

Als sectie Endpoins leeg, er zijn twee opties mogelijk:

  1. er zijn geen pods met het juiste label (hint: controleer of de naamruimte correct is geselecteerd);
  2. Er staat een fout in de servicelabels in de selector.

Als u een lijst met eindpunten ziet, maar nog steeds geen toegang hebt tot de applicatie, is de waarschijnlijke boosdoener een bug targetPort in de dienstbeschrijving.

Hoe controleer ik de functionaliteit van de dienst?

Ongeacht het type service kunt u de opdracht gebruiken kubectl port-forward om er verbinding mee te maken:

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

Здесь:

  • <service-name> — dienstnaam;
  • 3000 is de poort die u op de computer opent;
  • 80 - poort aan de servicezijde.

3. Ingress-diagnostiek

Als je tot nu toe hebt gelezen, dan:

  • peulen worden vermeld als Running и Ready;
  • de service verdeelt het verkeer met succes over de pods.

U kunt de app echter nog steeds niet bereiken.

Dit betekent dat de Ingress-controller hoogstwaarschijnlijk niet correct is geconfigureerd. Omdat de Ingress-controller een onderdeel van derden in het cluster is, zijn er verschillende foutopsporingsmethoden, afhankelijk van het type.

Maar voordat u speciale tools gebruikt om Ingress te configureren, kunt u iets heel eenvoudigs doen. Ingress-gebruik serviceName и servicePort om verbinding te maken met de dienst. U moet controleren of ze correct zijn geconfigureerd. U kunt dit doen met behulp van het commando:

kubectl describe ingress <ingress-name>

Als kolom Backend leeg is, is de kans op een configuratiefout groot. Als de backends aanwezig zijn, maar de applicatie nog steeds niet toegankelijk is, kan het probleem te maken hebben met:

  • Ingress-toegankelijkheidsinstellingen vanaf het openbare internet;
  • clustertoegankelijkheidsinstellingen van het openbare internet.

U kunt problemen met de infrastructuur identificeren door rechtstreeks verbinding te maken met de Ingress-pod. Om dit te doen, zoekt u eerst de Ingress Controller-pod (deze bevindt zich mogelijk in een andere naamruimte):

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 de opdracht describeom de poort in te stellen:

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

Maak ten slotte verbinding met de pod:

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

Nu worden alle verzoeken om poort 3000 op de computer omgeleid naar poort 80 van de pod.

Werkt het nu?

  • Zo ja, dan ligt het probleem bij de infrastructuur. Het is noodzakelijk om erachter te komen hoe het verkeer precies naar het cluster wordt gerouteerd.
  • Als dit niet het geval is, ligt het probleem bij de Ingress-controller.

Als u de Ingress-controller niet kunt laten werken, moet u fouten opsporen.

Er zijn veel varianten van Ingress-controllers. De meest populaire zijn Nginx, HAProxy, Traefik, enz. (voor meer informatie over bestaande oplossingen, zie onze recensie — ca. vert.) Raadpleeg de probleemoplossingsgids in de relevante controllerdocumentatie. Omdat de Ingang Nginx de populairste Ingress-controller is, hebben we in het artikel enkele tips opgenomen om hiermee verband houdende problemen op te lossen.

Foutopsporing in de Ingress Nginx-controller

Het Ingress-nginx-project heeft een ambtenaar plug-in voor kubectl. Team kubectl ingress-nginx kan worden gebruikt voor:

  • analyse van logs, backends, certificaten, enz.;
  • verbindingen met Ingress;
  • het bestuderen van de huidige configuratie.

De volgende drie commando's helpen je hierbij:

  • kubectl ingress-nginx lint - cheques nginx.conf;
  • kubectl ingress-nginx backend — onderzoekt de backend (vergelijkbaar met kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs — controleert de logboeken.

Houd er rekening mee dat u in sommige gevallen mogelijk de juiste naamruimte voor de Ingress-controller moet opgeven met behulp van de vlag --namespace <name>.

Beknopt

Het oplossen van problemen met Kubernetes kan een uitdaging zijn als u niet weet waar u moet beginnen. Je moet het probleem altijd van onderop benaderen: begin met pods en ga dan verder met de service en Ingress. De foutopsporingstechnieken die in dit artikel worden beschreven, kunnen op andere objecten worden toegepast, zoals:

  • inactieve banen en CronJobs;
  • StatefulSets en DaemonSets.

Ik betuig mijn dankbaarheid Gergely Risko, Daniël Weibel и Charles Christyraj voor waardevolle opmerkingen en aanvullingen.

PS van vertaler

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie