Przyp. tłum.: Ten artykuł jest częścią publikowanych w wolnym dostępie materiałów projektu , 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.

TL;DR: oto schemat, który pomoże Ci debugować wdrożenie w Kubernetes:
Schemat blokowy do znajdowania i naprawiania błędów w klastrze. W oryginale (po angielsku) jest dostępny w i .
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.

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

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

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:
- Selector (
selector) usługi musi pasować do przynajmniej jednej etykiety Pod'a. -
targetPortmusi zgadzać się zcontainerPortkontenera wewnątrz Pod'a. -
portUsł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:

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

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

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

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

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-labelsLub, 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:80Gdzie:
-
service/<service name>— nazwa usługi; w naszym przypadku tomy-service; - 3000 — port, który należy otworzyć na komputerze,
- 80 — port wpisany w polu
portusł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:
-
servicePortw Ingress musi odpowiadać parametrowiportw Service; -
serviceNamew Ingress musi zgadzać się z polemnamew Service.
Następny schemat podsumowuje połączenie portów:
1) Jak już wiesz, Service nasłuchuje na pewnym port:

2) Ingress ma parametr, zwany servicePort:

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

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

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/TCPNa koniec połącz się z podem:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemTeraz 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 , powinieneś zobaczyć stronę utworzoną przez aplikację.
Podsumowanie dotyczące portów
Przypomnijmy sobie, jakie porty i etykiety muszą się zgadzać:
- Selektor w definicji Service musi odpowiadać etykietom poda;
-
targetPortw definicji Service musi odpowiadaćcontainerPortkontenerowi wewnątrz poda; -
portW definicji Service może być dowolny. Różne usługi mogą korzystać z tego samego portu, ponieważ mają różne adresy IP; -
servicePortIngress musi zgadzać się zportw definicji Service; - Nazwa usługi musi zgadzać się z polem
serviceNamew 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.
- Najpierw musisz upewnić się, że pody działają, a następnie...
- Sprawdzić, czy usługa dostarcza ruch do podów, a potem...
- 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:

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

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

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:
-
kubectl logspozwala na pobranie logów z kontenerów w podzie; -
kubectl describe podpozwala na przeglądanie listy zdarzeń związanych z podem; -
kubectl get podpozwala na uzyskanie YAML-konfiguracji poda, przechowywanej w Kubernetes; -
kubectl exec -ti bashpozwala 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;
- Obraz jest przechowywany w prywatnym rejestrze, a Kubernetes nie ma uprawnień do jego odczytu.
- 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
- jest przykład
jak można to zrobić. , 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
- Test Liveness nie powiódł się za dużo razy.
- Kontener ;
- 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
- ResourceQuota
- Obiekt został zainstalowany w odpowiedniej przestrzeni nazw
ResourceQuotaUtworzenie pod'a spowoduje, że przestrzeń nazw przekroczy limit kwoty. - 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.creationTimestampPody 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:
- brak jakiegokolwiek pod'a z poprawną etykietą (wskazówka: sprawdź, czy namespace jest wybrany poprawnie);
- 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:80Gdzie:
-
<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
RunningiGotowy; - 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 PortsNa koniec połącz się z podem:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemTeraz 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 — przyp. tłum.) Należy skorzystać z podręcznika rozwiązywania problemów w dokumentacji odpowiedniego kontrolera. Ponieważ 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 . 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— sprawdzanginx.conf; -
kubectl ingress-nginx backend— bada backend (analogicznie dokubectl 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 , i za cenne uwagi i dodatki.
P.S. od tłumacza
Przeczytaj także na naszym blogu:
- «»;
- «»;
- «»;
- «».
Źródło: habr.com
