Wizualny poradnik do diagnostyki problemów w Kubernetes

Przyp. tłum.: Ten artykuł jest częścią publikowanych w wolnym dostępie materiałów projektu learnk8s, szkolenia dla osób pracujących z Kubernetes oraz indywidualnych administratorów. W nim Daniele Polencic, kierownik projektu, dzieli się wizualną instrukcją, jakie kroki podjąć w przypadku ogólnych problemów z aplikacjami uruchomionymi w klastrze K8s.

Wizualny poradnik do diagnostyki problemów w Kubernetes

TL;DR: oto schemat, który pomoże Ci debugować wdrożenie w Kubernetes:

Wizualny poradnik do diagnostyki problemów w Kubernetes

Schemat blokowy do znajdowania i naprawiania błędów w klastrze. W oryginale (po angielsku) jest dostępny w PDF i jako obrazek.

Podczas wdrażania aplikacji w Kubernetes zazwyczaj trzeba określić trzy składniki:

  • Deployment — to pewien przepis do tworzenia kopii aplikacji, zwanych podami;
  • Service — wewnętrzny równoważnik obciążenia, który rozdziela ruch między podami;
  • Ingress — opis jak ruch będzie kierowany z zewnętrznego świata do Service’u.

Oto krótkie graficzne podsumowanie:

1) W Kubernetes aplikacje otrzymują ruch z zewnętrznego świata przez dwa poziomy równoważników obciążenia: wewnętrzny i zewnętrzny.

Wizualny poradnik do diagnostyki problemów w Kubernetes

2) Wewnętrzny równoważnik nazywa się Service, zewnętrzny – Ingress.

Wizualny poradnik do diagnostyki problemów w Kubernetes

3) Deployment tworzy pody i monitoruje je (nie są tworzone ręcznie).

Wizualny poradnik do diagnostyki problemów w Kubernetes

Załóżmy, że chcesz wdrożyć prostą aplikację typu Hello World. Konfiguracja YAML dla niej będzie wyglądać następująco:

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: /

Definicja jest dość długa i łatwo jest się zaplątać, jak składniki są ze sobą powiązane.

Na przykład:

  • Kiedy należy używać portu 80, a kiedy — 8080?
  • Czy należy tworzyć nowy port dla każdej usługi, aby nie miały konfliktów?
  • Czy nazwy etykiet mają znaczenie? Czy muszą być identyczne wszędzie?

Zanim skoncentrujemy się na debugowaniu, przypomnijmy sobie, jak trzy składniki są połączone. Zacznijmy od Deployment i Service.

Połączenie między Deploymentem a Service

Możesz być zaskoczony, ale Deploymenty i Service’y nie są ze sobą bezpośrednio połączone. Zamiast tego, Service bezpośrednio wskazuje na Pody, omijając Deployment.

Zatem interesuje nas, jak połączone są ze sobą Pod'y i Service'y. Należy pamiętać o trzech rzeczach:

  1. Selector (selector) usługi musi pasować do przynajmniej jednej etykiety Pod'a.
  2. targetPort musi zgadzać się z containerPort kontenera wewnątrz Pod'a.
  3. port Usługa może być dowolna. Różne usługi mogą używać tego samego portu, ponieważ mają różne adresy IP.

Następny schemat przedstawia wszystko powyższe w formie graficznej:

1) Załóżmy, że usługa kieruje ruch do pewnego pod:

Wizualny poradnik do diagnostyki problemów w Kubernetes

2) Podczas tworzenia pod'a należy określić containerPort dla każdego kontenera w pod'ach:

Wizualny poradnik do diagnostyki problemów w Kubernetes

3) Przy tworzeniu usługi należy określić port i targetPort. Ale przez który z nich następuje połączenie z kontenerem?

Wizualny poradnik do diagnostyki problemów w Kubernetes

4) Przez targetPort. Musi zgadzać się z containerPort.

Wizualny poradnik do diagnostyki problemów w Kubernetes

5) Przypuśćmy, że w kontenerze otwarty jest port 3000. W takim razie wartość targetPort powinna być taka sama.

Wizualny poradnik do diagnostyki problemów w Kubernetes

W pliku YAML etykiety i porty / targetPort muszą się zgadzać:

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  # <<<

A co z etykietą track: canary w górnej części sekcji Deployment? Czy powinna być zgodna?

Ta etykieta odnosi się do wdrażania i nie jest używana przez usługę do kierowania ruchem. Innymi słowy, można ją usunąć lub przypisać inną wartość.

A co z selektorem matchLabels?

Zawsze musi zgadzać się z etykietami Pod'a, ponieważ jest używany przez Deployment do śledzenia pod'ów.

Załóżmy, że wprowadziłeś poprawne zmiany. Jak je sprawdzić?

Można sprawdzić etykiety pod'ów za pomocą następującego polecenia:

kubectl get pods --show-labels

Lub, jeśli pod'y należą do kilku aplikacji:

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

Gdzie any-name=my-app — to jest etykieta any-name: my-app.

Masz jeszcze problemy?

Możesz połączyć się z pod'em! W tym celu musisz użyć polecenia port-forward w kubectl. Umożliwia to połączenie z usługą i sprawdzenie połączenia.

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

Gdzie:

  • service/<service name> — nazwa usługi; w naszym przypadku to my-service;
  • 3000 — port, który należy otworzyć na komputerze,
  • 80 — port wpisany w polu port usługi.

Jeśli udało się nawiązać połączenie, oznacza to, że ustawienia są poprawne.

Jeśli nie udało się nawiązać połączenia, problem leży w etykietach lub porty się nie zgadzają.

Połączenie Service oraz Ingress

Następnym krokiem w zapewnieniu dostępu do aplikacji jest skonfigurowanie Ingress. Ingress musi wiedzieć, jak znaleźć serwis, a następnie zlokalizować pody i kierować do nich ruch. Ingress znajduje odpowiedni serwis po nazwie i otwartym porcie.

W opisie Ingress i Service muszą zgadzać się dwa parametry:

  1. servicePort w Ingress musi odpowiadać parametrowi port w Service;
  2. serviceName w Ingress musi zgadzać się z polem name w Service.

Następny schemat podsumowuje połączenie portów:

1) Jak już wiesz, Service nasłuchuje na pewnym port:

Wizualny poradnik do diagnostyki problemów w Kubernetes

2) Ingress ma parametr, zwany servicePort:

Wizualny poradnik do diagnostyki problemów w Kubernetes

3) Ten parametr (servicePort) zawsze musi odpowiadać port w definicji Service:

Wizualny poradnik do diagnostyki problemów w Kubernetes

4) Jeśli w Service określono port 80, to ważne jest, aby servicePort także był równy 80:

Wizualny poradnik do diagnostyki problemów w Kubernetes

W praktyce należy zwrócić uwagę na następujące linie:

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: /

Jak sprawdzić, czy Ingress działa?

Można skorzystać z metody z kubectl port-forward, ale zamiast serwisu należy połączyć się z kontrolerem Ingress.

Najpierw musisz poznać nazwę poda z kontrolerem Ingress:

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

Znajdź pod Ingress (może się odnosić do innej przestrzeni nazw) i wykonaj polecenie describe, aby sprawdzić numery portów:

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

Na koniec połącz się z podem:

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

Teraz za każdym razem, gdy wyślesz żądanie na port 3000 na komputerze, będzie ono przekierowywane na port 80 poda z kontrolerem Ingress. Po przejściu na http://localhost:3000, powinieneś zobaczyć stronę utworzoną przez aplikację.

Podsumowanie dotyczące portów

Przypomnijmy sobie, jakie porty i etykiety muszą się zgadzać:

  1. Selektor w definicji Service musi odpowiadać etykietom poda;
  2. targetPort w definicji Service musi odpowiadać containerPort kontenerowi wewnątrz poda;
  3. port W definicji Service może być dowolny. Różne usługi mogą korzystać z tego samego portu, ponieważ mają różne adresy IP;
  4. servicePort Ingress musi zgadzać się z port w definicji Service;
  5. Nazwa usługi musi zgadzać się z polem serviceName w Ingressie.

Niestety, nie wystarczy wiedzieć, jak prawidłowo skonfigurować YAML.

Co się dzieje, gdy coś poszło nie tak?

Możliwe, że pod nie uruchamia się lub pada.

3 kroki do diagnozowania problemów z aplikacjami w Kubernetes

Zanim przystąpisz do debugowania deploymentu, musisz mieć dobrą wiedzę o tym, jak działa Kubernetes.

Ponieważ w każdej aplikacji wdrożonej w K8s są trzy komponenty, debugowanie należy przeprowadzać w określonej kolejności, zaczynając od najniższego.

  1. Najpierw musisz upewnić się, że pody działają, a następnie...
  2. Sprawdzić, czy usługa dostarcza ruch do podów, a potem...
  3. Sprawdzić, czy Ingress jest poprawnie skonfigurowany.

Wizualna prezentacja:

1) Poszukiwanie problemów należy zacząć od dołu. Najpierw sprawdź, czy pody mają statusy Gotowy i Running:

Wizualny poradnik do diagnostyki problemów w Kubernetes

2) Jeśli pody są gotowe (Gotowy), należy ustalić, czy usługa rozprowadza ruch między podami:

Wizualny poradnik do diagnostyki problemów w Kubernetes

3) Na koniec należy przeanalizować połączenie usługi i Ingressu:

Wizualny poradnik do diagnostyki problemów w Kubernetes

1. Diagnostyka podów

W większości przypadków problem jest związany z podami. Upewnij się, że pody są oznaczone jako Gotowy i Running. Można to sprawdzić za pomocą polecenia:

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

W wyniku powyższego polecenia, ostatni pod jest oznaczony jako Running i Gotowy, ale w przypadku dwóch pozostałych nie jest.

Jak zrozumieć, co poszło nie tak?

Są cztery przydatne polecenia do diagnozowania podów:

  1. kubectl logs pozwala na pobranie logów z kontenerów w podzie;
  2. kubectl describe pod pozwala na przeglądanie listy zdarzeń związanych z podem;
  3. kubectl get pod pozwala na uzyskanie YAML-konfiguracji poda, przechowywanej w Kubernetes;
  4. kubectl exec -ti bash pozwala na uruchomienie interaktywnej powłoki w jednym z kontenerów poda.

Które z nich wybrać?

Faktem jest, że nie ma uniwersalnego polecenia. Należy użyć ich kombinacji.

Typowe problemy z podami

Są dwa podstawowe typy błędów podów: błędy podczas uruchamiania (startup) i błędy w czasie wykonywania (runtime).

Błędy uruchamiania:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • NiepoprawnaNazwaObrazu

Błędy czasu wykonania:

  • CrashLoopBackOff
  • BłądUruchomieniaKontejnera
  • BłądZabiciaKontejnera
  • BłądWeryfikacjiNieRoota
  • BłądUruchomieniaKontejneraInicjującego
  • BłądTworzeniaPodSandboxu
  • BłądKonfiguracjiPodSandboxu
  • BłądZabiciaPodSandboxu
  • Niektóre błędy występują częściej niż inne. Oto kilka najczęściej spotykanych błędów i sposoby ich rozwiązania.
  • ImagePullBackOff

Ten błąd pojawia się, gdy Kubernetes nie może pobrać obrazu dla jednego z kontenerów w podzie. Oto trzy najczęstsze powody tego:

Niepoprawnie podana nazwa obrazu — na przykład, popełniono w nim błąd lub obraz nie istnieje;

Podano nieistniejący tag obrazu;

  1. Obraz jest przechowywany w prywatnym rejestrze, a Kubernetes nie ma uprawnień do jego odczytu.
  2. Pierwsze dwa powody są łatwe do rozwiązania — wystarczy poprawić nazwę obrazu i tag. W przypadku ostatniego należy wprowadzić dane uwierzytelniające do prywatnego rejestru w Secret i dodać odwołania do niego w podach. W dokumentacji Kubernetes
  3. jest przykład

jak można to zrobić. Kubernetes wyświetla błąd , jeśli kontener nie może się uruchomić. Zwykle dzieje się tak, gdy:

CrashLoopBackOff

W aplikacji występuje błąd, który uniemożliwia jej uruchomienie; CrashLoopBackOffjest skonfigurowana niepoprawnie

  1. Test Liveness nie powiódł się za dużo razy.
  2. Kontener Należy spróbować uzyskać logi z kontenera, aby ustalić przyczynę jego awarii. Jeśli dostęp do logów jest trudny, ponieważ kontener zbyt szybko się restartuje, można użyć następującej komendy:;
  3. kubectl logs --previous

Wyświetla komunikaty o błędach z poprzedniej reinkarnacji kontenera.

Ten błąd występuje, gdy kontener nie jest w stanie się uruchomić. Odpowiada momentowi przed uruchomieniem aplikacji. Zwykle jego przyczyną jest niepoprawna konfiguracja, na przykład:

próba zamontowania nieistniejącego wolumenu, takiego jak ConfigMap lub Secrets;

BłądUruchomieniaKontejnera

próba zamontowania wolumenu typu tylko do odczytu jako do zapisu.

  • Do analizy takich błędów dobrze sprawdza się komenda
  • kubectl describe pod

Pody w stanie Pending Po utworzeniu pod pozostaje w stanie.

Dlaczego tak się dzieje?

Oto możliwe powody (zakładam, że scheduler działa poprawnie): Pending.

W klastrze brakuje zasobów, takich jak moc obliczeniowa i pamięć, do uruchomienia poda.

W odpowiedniej przestrzeni nazw zainstalowano obiekt

  1. ResourceQuota
  2. Obiekt został zainstalowany w odpowiedniej przestrzeni nazw ResourceQuota Utworzenie pod'a spowoduje, że przestrzeń nazw przekroczy limit kwoty.
  3. Pod jest przypisany do Pending PersistentVolumeClaim.

W takim przypadku zaleca się użycie polecenia kubectl describe i sprawdzenie sekcji Wydarzenia:

kubectl describe pod

W przypadku błędów związanych z ResourceQuotas, zaleca się przeglądanie logów klastra za pomocą polecenia

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

Pody nie są w stanie Ready

Jeśli pod jest oznaczony jako Running, ale nie znajduje się w stanie Gotowy, to znaczy, że sprawdzenie jego gotowości (readiness probe) nie powiodło się.

Kiedy to się dzieje, pod nie łączy się z usługą, a ruch do niego nie dociera. Niepowodzenie testu gotowości jest spowodowane problemami z aplikacją. W takim przypadku, aby zlokalizować błąd, należy przeanalizować sekcję Wydarzenia w wyniku polecenia kubectl describe.

2. Diagnostyka usług

Jeśli pody są oznaczone jako Running i Gotowy, ale wciąż nie ma odpowiedzi od aplikacji, należy sprawdzić ustawienia usługi.

Usługi zajmują się routowaniem ruchu do pod'ów w zależności od ich etykiet. Dlatego pierwszą rzeczą, którą należy zrobić, jest sprawdzenie, ile pod'ów działa z usługą. W tym celu można sprawdzić endpointy w usłudze:

kubectl describe service  | grep Endpoints

Endpoint to para wartości w formacie <IP-адрес:порт>, a w wyniku powinny być obecne przynajmniej jedna taka para (to znaczy, że z usługą działa przynajmniej jeden pod).

Jeśli sekcja Endpoints jest pusta, możliwe są dwie opcje:

  1. brak jakiegokolwiek pod'a z poprawną etykietą (wskazówka: sprawdź, czy namespace jest wybrany poprawnie);
  2. wystąpił błąd w etykietach usługi w selektorze.

Jeśli widzisz listę endpointów, ale wciąż nie możesz uzyskać dostępu do aplikacji, prawdopodobnym powodem jest błąd w targetPort opisie usługi.

Jak sprawdzić działanie usługi?

Niezależnie od typu usługi, można użyć polecenia kubectl port-forward do połączenia się z nią:

kubectl port-forward service/ 3000:80

Gdzie:

  • <service-name> – nazwa usługi;
  • 3000 – port, który otwierasz na komputerze;
  • 80 – port po stronie usługi.

3. Diagnostyka Ingress

Jeśli dotarłeś do tego miejsca, to:

  • pody są oznaczone jako Running i Gotowy;
  • usługa skutecznie rozprowadza ruch do pod'ów.

Jednak nadal nie możesz 'dostukać' się do aplikacji.

Oznacza to, że prawdopodobnie kontroler Ingress jest źle skonfigurowany. Ponieważ kontroler Ingress jest komponentem zewnętrznym w klastrze, istnieją różne metody debugowania w zależności od jego typu.

Ale zanim sięgniesz po specjalne narzędzia do konfiguracji Ingressa, możesz wykonać coś bardzo prostego. Ingress używa serviceName i servicePort do łączenia z usługą. Należy sprawdzić, czy są one poprawnie skonfigurowane. Można to zrobić za pomocą komendy:

kubectl describe ingress

Jeśli kolumna Backend jest pusta, istnieje duże prawdopodobieństwo błędu w konfiguracji. Jeśli backendy są na miejscu, ale nadal nie ma dostępu do aplikacji, problem może być związany z:

  • ustawieniami dostępności Ingressa z publicznego internetu;
  • ustawieniami dostępności klastra z publicznego internetu.

Aby zidentyfikować problemy z infrastrukturą, można się połączyć bezpośrednio z podem Ingressa. W tym celu najpierw znajdź pod kontrolera Ingress (może znajdować się w innym 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

Skorzystaj z komendy describe, aby ustawić port:

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

Na koniec połącz się z podem:

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

Teraz wszystkie żądania na porcie 3000 na komputerze będą przekierowywane na port 80 poda.

Czy działa teraz?

  • Jeśli tak, to problem z infrastrukturą. Należy ustalić, w jaki sposób odbywa się routowanie ruchu do klastra.
  • Jeśli nie, to problem z kontrolerem Ingress.

Jeśli nie uda się uruchomić kontrolera Ingress, konieczne będzie jego debugowanie.

Istnieje wiele rodzajów kontrolerów Ingress. Najpopularniejsze to Nginx, HAProxy, Traefik i inne. (więcej o dostępnych rozwiązaniach zobacz w naszym przeglądzie — przyp. tłum.) Należy skorzystać z podręcznika rozwiązywania problemów w dokumentacji odpowiedniego kontrolera. Ponieważ Ingress Nginx jest najpopularniejszym kontrolerem Ingress, do artykułu dodaliśmy kilka wskazówek dotyczących rozwiązywania z nim związanych problemów.

Debugowanie kontrolera Ingress Nginx

Projekt Ingress-nginx ma oficjalny plugin dla kubectl. Komenda kubectl ingress-nginx może być używana do:

  • analizy logów, backendów, certyfikatów itp.;
  • łączenia się z Ingressem;
  • przeglądania bieżącej konfiguracji.

Pomogą Ci w tym następujące trzy komendy:

  • kubectl ingress-nginx lint — sprawdza nginx.conf;
  • kubectl ingress-nginx backend — bada backend (analogicznie do kubectl describe ingress);
  • kubectl ingress-nginx logs — sprawdza logi.

Uwaga: w niektórych przypadkach może być konieczne podanie poprawnego namespace dla kontrolera Ingress za pomocą flagi --namespace.

Podsumowanie

Diagnostyka w Kubernetes może się okazać skomplikowanym zadaniem, jeśli nie wiadomo, od czego zacząć. Należy podchodzić do problemu według zasady 'od dołu do góry': zaczynaj od podów, a następnie przechodź do usług i Ingressu. Metody debugowania opisane w artykule można stosować również do innych obiektów, takich jak:

  • nie działające Joby i CronJoby;
  • StatefulSety i DaemonSety.

Składam podziękowania Gergely Risko, Daniel Weibel i Charles Christyraj za cenne uwagi i dodatki.

P.S. od tłumacza

Przeczytaj także na naszym blogu:

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster