Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

Notatka. przeł.: Ten artykuł jest częścią materiałów projektu opublikowanych w domenie publicznej ucz się8s, firmy szkoleniowe i indywidualni administratorzy do pracy z Kubernetesem. W nim Daniele Polencic, kierownik projektu, dzieli się wizualnymi instrukcjami, jakie kroki należy podjąć w przypadku ogólnych problemów z aplikacjami działającymi na klastrze K8s.

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

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

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

Schemat blokowy wyszukiwania i naprawiania błędów w klastrze. Oryginał (w języku angielskim) jest dostępny pod adresem PDF и jako zdjęcie.

Podczas wdrażania aplikacji w Kubernetes zazwyczaj należy zdefiniować trzy komponenty:

  • Rozlokowanie - jest to swego rodzaju przepis na tworzenie kopii aplikacji, zwanych podami;
  • Usługi — wewnętrzny moduł równoważenia obciążenia rozdzielający ruch pomiędzy podami;
  • Ingres — opis sposobu, w jaki ruch ze świata zewnętrznego będzie kierowany do Usługi.

Oto krótkie podsumowanie graficzne:

1) W Kubernetesie aplikacje odbierają ruch ze świata zewnętrznego poprzez dwie warstwy modułów równoważenia obciążenia: wewnętrzną i zewnętrzną.

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

2) Wewnętrzny balanser nazywa się Service, zewnętrzny nazywa się Ingress.

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

3) Wdrożenie tworzy pody i monitoruje je (nie są one tworzone ręcznie).

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

Załóżmy, że chcesz wdrożyć prostą aplikację a la Witaj świecie. Konfiguracja YAML 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 się pomylić, jeśli chodzi o wzajemne powiązania komponentów.

Na przykład:

  • Kiedy należy używać portu 80, a kiedy 8080?
  • Czy powinienem utworzyć nowy port dla każdej usługi, aby nie powodowały konfliktów?
  • Czy nazwy etykiet mają znaczenie? Czy wszędzie powinny być takie same?

Zanim skupimy się na debugowaniu, pamiętajmy, jak te trzy komponenty są ze sobą powiązane. Zacznijmy od wdrożenia i serwisu.

Związek między wdrożeniem a usługą

Będziesz zaskoczony, ale wdrożenie i serwis nie są ze sobą w żaden sposób powiązane. Zamiast tego usługa wskazuje bezpośrednio Pody, pomijając wdrożenie.

Dlatego jesteśmy zainteresowani tym, jak Pody i Usługi są ze sobą powiązane. Trzy rzeczy do zapamiętania:

  1. Selektor (selector) dla usługi musi odpowiadać co najmniej jednej etykiecie Poda.
  2. targetPort musi pasować containerPort pojemnik wewnątrz kapsuły.
  3. port Usługa może być dowolna. Różne usługi mogą korzystać z tego samego portu, ponieważ mają różne adresy IP.

Poniższy diagram przedstawia wszystkie powyższe w formie graficznej:

1) Wyobraź sobie, że usługa kieruje ruch do określonego poda:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

2) Tworząc pod, musisz określić containerPort dla każdego pojemnika w strąkach:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

3) Tworząc usługę, musisz określić port и targetPort. Ale który służy do podłączenia do kontenera?

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

4) Przez targetPort. To musi pasować containerPort.

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

5) Załóżmy, że w kontenerze jest otwarty port 3000. Następnie wartość targetPort powinno być takie samo.

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

W pliku YAML etykiety i ports / targetPort musi pasować:

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 na górze sekcji Wdrożenie? Czy powinno pasować?

Ta etykieta jest specyficzna dla wdrożenia i nie jest używana przez usługę do kierowania ruchu. Inaczej mówiąc, można go usunąć lub przypisać mu inną wartość.

A co z selektorem matchLabels?

Musi zawsze pasować do etykiet kapsuły, ponieważ jest używany przez Deployment do śledzenia podów.

Załóżmy, że dokonałeś poprawnych zmian. Jak je sprawdzić?

Możesz sprawdzić etykietę kapsuły za pomocą następującego polecenia:

kubectl get pods --show-labels

Lub, jeśli pody należą do kilku aplikacji:

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

Где any-name=my-app jest etykietą any-name: my-app.

Czy pozostały jakieś trudności?

Można połączyć się z kapsułą! Aby to zrobić, musisz użyć polecenia port-forward w kubectl. Umożliwia połączenie się z usługą i sprawdzenie połączenia.

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

Tutaj:

  • service/<service name> - Nazwa serwisu; w naszym przypadku tak my-service;
  • 3000 to port, który należy otworzyć na komputerze;
  • 80 - port określony w polu port praca.

Jeśli połączenie zostało nawiązane, ustawienia są prawidłowe.

Jeśli połączenie nie powiedzie się, oznacza to problem z etykietami lub porty nie pasują.

Związek między usługą a wejściem

Kolejnym krokiem w zapewnieniu dostępu do aplikacji jest skonfigurowanie Ingress. Ingress musi wiedzieć, jak znaleźć usługę, a następnie znaleźć pody i skierować do nich ruch. Ingress wyszukuje wymaganą usługę według nazwy i otwartego portu.

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

  1. servicePort w Ingress musi odpowiadać parametrowi port czynny;
  2. serviceName w Ingress musi pasować do pola name czynny.

Poniższy diagram podsumowuje połączenia portów:

1) Jak już wiesz, Serwis słucha pewnych port:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

2) Ingress ma parametr o nazwie servicePort:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

3) Ten parametr (servicePort) musi zawsze pasować port w definicji Usługi:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

4) Jeśli w serwisie określono port 80, jest to konieczne servicePort było również równe 80:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

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żesz użyć metody z kubectl port-forward, ale zamiast usługi musisz połączyć się z kontrolerem Ingress.

Najpierw musisz znaleźć nazwę kapsuły za pomocą kontrolera 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ź moduł Ingress (może znajdować się w innej przestrzeni nazw) i uruchom polecenie describeaby znaleźć 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 kapsułą:

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

Teraz za każdym razem, gdy wysyłasz żądanie do portu 3000 na swoim komputerze, zostanie ono przekazane do portu 80 kapsuły z kontrolerem Ingress. Idąc http://localhost:3000, powinieneś zobaczyć stronę wygenerowaną przez aplikację.

Podsumowanie portów

Przypomnijmy jeszcze raz, które porty i etykiety muszą pasować:

  1. Selektor w definicji usługi musi odpowiadać etykiecie poda;
  2. targetPort w definicji Usługa musi być zgodna containerPort pojemnik wewnątrz kapsuły;
  3. port w definicji Usługa może być czymkolwiek. Różne usługi mogą korzystać z tego samego portu, ponieważ mają różne adresy IP;
  4. servicePort Ingres musi się zgadzać port w definicji Usługi;
  5. Nazwa usługi musi być zgodna z polem serviceName w Ingressie.

Niestety, nie wystarczy wiedzieć, jak poprawnie ustrukturyzować konfigurację YAML.

Co się stanie, gdy coś pójdzie nie tak?

Pod może się nie uruchomić lub może ulec awarii.

3 kroki do diagnozowania problemów z aplikacjami w Kubernetesie

Zanim zaczniesz debugować wdrożenie, musisz dobrze zrozumieć, jak działa Kubernetes.

Ponieważ każda aplikacja pobrana w K8s ma trzy komponenty, należy je debugować w określonej kolejności, zaczynając od samego dołu.

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

Reprezentacja wizualna:

1) Należy zacząć szukać problemów od samego dołu. Najpierw sprawdź, czy pody mają statusy Ready и Running:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

2) Jeśli strąki są gotowe (Ready), warto dowiedzieć się, czy usługa dystrybuuje ruch pomiędzy podami:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

3) Na koniec musisz przeanalizować połączenie między usługą a Ingressem:

Wizualny przewodnik po rozwiązywaniu problemów z Kubernetesem

1. Diagnostyka strąków

W większości przypadków problem dotyczy kapsuły. Upewnij się, że kapsuły są wymienione jako Ready и Running. Możesz 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 wynikach powyższego polecenia ostatni zasobnik jest wymieniony jako Running и Readynie dotyczy to jednak dwóch pozostałych.

Jak zrozumieć, co poszło nie tak?

Istnieją cztery przydatne polecenia do diagnozowania zasobników:

  1. kubectl logs <имя pod'а> umożliwia wyodrębnienie logów z kontenerów w pod;
  2. kubectl describe pod <имя pod'а> umożliwia przeglądanie listy zdarzeń powiązanych z podem;
  3. kubectl get pod <имя pod'а> pozwala uzyskać konfigurację YAML poda przechowywanego w Kubernetesie;
  4. kubectl exec -ti <имя pod'а> bash umożliwia uruchomienie interaktywnej powłoki poleceń w jednym z kontenerów pod

Który wybrać?

Faktem jest, że nie ma uniwersalnego polecenia. Należy zastosować ich kombinację.

Typowe problemy z kapsułą

Istnieją dwa główne typy błędów podów: błędy uruchamiania i błędy czasu wykonywania.

Błędy uruchamiania:

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

Błędy wykonania:

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

Niektóre błędy występują częściej niż inne. Oto niektóre z najczęstszych błędów i sposoby ich naprawienia.

ObrazPullBackOff

Ten błąd występuje, gdy Kubernetes nie może uzyskać obrazu dla jednego z kontenerów podów. Oto trzy najczęstsze przyczyny takiego stanu rzeczy:

  1. Nazwa obrazu jest niepoprawna - na przykład popełniłeś w niej błąd lub obraz nie istnieje;
  2. Dla obrazu określono nieistniejący tag;
  3. Obraz jest przechowywany w prywatnym rejestrze i Kubernetes nie ma uprawnień dostępu do niego.

Pierwsze dwa powody są łatwe do wyeliminowania – wystarczy poprawić nazwę obrazu i tag. W tym drugim przypadku należy wprowadzić dane uwierzytelniające zamknięty rejestr w Secret i dodać do niego linki w podach. W dokumentacji Kubernetesa jest przykład jak można to zrobić.

Wycofanie pętli awarii

Kubenetes zgłasza błąd CrashLoopBackOff, jeśli kontener nie może zostać uruchomiony. Zwykle dzieje się tak, gdy:

  1. W aplikacji występuje błąd uniemożliwiający jej uruchomienie;
  2. pojemnik skonfigurowany nieprawidłowo;
  3. Test żywotności nie powiódł się zbyt wiele razy.

Musisz spróbować dostać się do logów z kontenera, żeby poznać przyczynę jego niepowodzenia. Jeśli dostęp do logów jest utrudniony ze względu na zbyt szybkie ponowne uruchomienie kontenera, możesz użyć następującego polecenia:

kubectl logs <pod-name> --previous

Wyświetla komunikaty o błędach z poprzedniego wcielenia kontenera.

Błąd RunContainer

Ten błąd występuje, gdy nie można uruchomić kontenera. Odpowiada momentowi przed uruchomieniem aplikacji. Zwykle jest to spowodowane nieprawidłowymi ustawieniami, na przykład:

  • próba zamontowania nieistniejącego woluminu, takiego jak ConfigMap lub Secrets;
  • próba zamontowania woluminu tylko do odczytu w trybie odczytu i zapisu.

Zespół świetnie nadaje się do analizy takich błędów kubectl describe pod <pod-name>.

Pody mają stan Oczekujące

Po utworzeniu kapsuła pozostaje w tym stanie Pending.

Dlaczego tak się dzieje?

Oto możliwe przyczyny (zakładam, że harmonogram działa poprawnie):

  1. Klaster nie ma wystarczających zasobów, takich jak moc obliczeniowa i pamięć, aby uruchomić zasobnik.
  2. Obiekt jest instalowany w odpowiedniej przestrzeni nazw ResourceQuota a utworzenie poda spowoduje, że przestrzeń nazw przekroczy limit.
  3. Pod jest powiązany z oczekującym PersistentVolumeClaim.

W takim przypadku zaleca się użycie polecenia kubectl describe i sprawdź sekcję Events:

kubectl describe pod <pod name>

W przypadku błędów dot ResourceQuotas, zaleca się przeglądanie dzienników klastra za pomocą polecenia

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

Pody nie są gotowe

Jeśli kapsuła jest wymieniona jako Running, ale nie jest w stanie Ready, oznacza sprawdzenie jego gotowości (sonda gotowości) kończy się niepowodzeniem.

W takiej sytuacji kapsuła nie łączy się z usługą i nie przepływa do niej żaden ruch. Niepowodzenie testu gotowości jest spowodowane problemami w aplikacji. W takim przypadku, aby znaleźć błąd, musisz przeanalizować sekcję Events w wynikach polecenia kubectl describe.

2. Diagnostyka serwisowa

Jeśli strąki są wymienione jako Running и Ready, ale nadal nie ma odpowiedzi ze strony aplikacji, powinieneś sprawdzić ustawienia usługi.

Usługi są odpowiedzialne za kierowanie ruchu do podów w zależności od ich etykiet. Dlatego pierwszą rzeczą, którą musisz zrobić, to sprawdzić, ile podów współpracuje z usługą. W tym celu możesz sprawdzić punkty końcowe w usłudze:

kubectl describe service <service-name> | grep Endpoints

Endpoint to para wartości formularza <IP-адрес:порт>i co najmniej jedna taka para musi być obecna na wyjściu (tzn. co najmniej jeden pod współpracuje z usługą).

Jeśli sekcja Endpoins pusty, możliwe są dwie opcje:

  1. nie ma podów z odpowiednią etykietą (podpowiedź: sprawdź, czy przestrzeń nazw została wybrana poprawnie);
  2. W selektorze występuje błąd w etykietach usług.

Jeśli widzisz listę punktów końcowych, ale nadal nie możesz uzyskać dostępu do aplikacji, prawdopodobnym winowajcą jest błąd targetPort w opisie usługi.

Jak sprawdzić funkcjonalność usługi?

Niezależnie od rodzaju usługi możesz skorzystać z polecenia kubectl port-forward aby się z nim połączyć:

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

Tutaj:

  • <service-name> - Nazwa serwisu;
  • 3000 to port, który otwierasz na komputerze;
  • 80 - port od strony serwisowej.

3. Diagnostyka ingresu

Jeśli doczytałeś aż dotąd, to:

  • strąki są wymienione jako Running и Ready;
  • usługa pomyślnie rozdziela ruch pomiędzy podami.

Jednak nadal nie możesz uzyskać dostępu do aplikacji.

Oznacza to, że kontroler Ingress najprawdopodobniej nie jest poprawnie skonfigurowany. Ponieważ kontroler ruchu przychodzącego jest komponentem innej firmy w klastrze, istnieją różne metody debugowania w zależności od jego typu.

Zanim jednak skorzystasz ze specjalnych narzędzi do konfiguracji Ingress, możesz zrobić coś bardzo prostego. Ingres wykorzystuje serviceName и servicePort aby połączyć się z usługą. Musisz sprawdzić, czy są one poprawnie skonfigurowane. Można to zrobić za pomocą polecenia:

kubectl describe ingress <ingress-name>

Jeśli kolumna Backend pusty, istnieje duże prawdopodobieństwo błędu konfiguracji. Jeśli backendy są już zainstalowane, ale aplikacja nadal jest niedostępna, problem może być związany z:

  • Ustawienia dostępności ruchu przychodzącego z publicznego Internetu;
  • ustawienia dostępności klastra z publicznego Internetu.

Możesz zidentyfikować problemy z infrastrukturą, łącząc się bezpośrednio z modułem Ingress. Aby to zrobić, najpierw znajdź moduł Ingress Controller (może znajdować się w innej przestrzeni nazw):

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

Użyj polecenia describeaby ustawić port:

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

Na koniec połącz się z kapsułą:

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

Teraz wszystkie żądania kierowane do portu 3000 na komputerze będą przekierowywane do portu 80 kapsuły.

Czy to działa teraz?

  • Jeśli tak, to problem leży w infrastrukturze. Konieczne jest dokładne sprawdzenie, w jaki sposób ruch kierowany jest do klastra.
  • Jeśli nie, problem dotyczy kontrolera Ingress.

Jeśli nie możesz uruchomić kontrolera Ingress, będziesz musiał go zdebugować.

Istnieje wiele odmian kontrolerów Ingress. Najpopularniejsze to Nginx, HAProxy, Traefik itp. (więcej informacji o istniejących rozwiązaniach zob nasza recenzja - około. tłumacz.) Należy zapoznać się z instrukcją rozwiązywania problemów w odpowiedniej dokumentacji sterownika. Ponieważ Wejdź do Nginxa to najpopularniejszy kontroler Ingress, w artykule zamieściliśmy kilka wskazówek, jak rozwiązać problemy z nim związane.

Debugowanie kontrolera Ingress Nginx

Projekt Ingress-nginx ma oficjalnego przedstawiciela wtyczka do kubectl. Zespół kubectl ingress-nginx może być stosowany do:

  • analiza logów, backendów, certyfikatów itp.;
  • połączenia z Ingresem;
  • przestudiowanie aktualnej konfiguracji.

Pomogą Ci w tym poniższe trzy polecenia:

  • kubectl ingress-nginx lint - czeki nginx.conf;
  • kubectl ingress-nginx backend — eksploruje backend (podobnie jak kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs — sprawdza logi.

Pamiętaj, że w niektórych przypadkach może być konieczne określenie poprawnej przestrzeni nazw dla kontrolera Ingress za pomocą flagi --namespace <name>.

Streszczenie

Rozwiązywanie problemów z Kubernetesem może być trudne, jeśli nie wiesz, od czego zacząć. Zawsze należy podejść do problemu od dołu do góry: zacząć od podów, a następnie przejść do usługi i Ingress. Techniki debugowania opisane w tym artykule można zastosować do innych obiektów, takich jak:

  • bezczynne zadania i CronJobs;
  • Zestawy stanowe i zestawy demonów.

wyrażam swoją wdzięczność Gergely'ego Risko, Daniela Weibela и Karola Christyraja za cenne uwagi i uzupełnienia.

PS od tłumacza

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz