Nota traducătorului.: Acest articol face parte din materialele publicate liber ale proiectului , dedicat formării în utilizarea Kubernetes pentru companii și administratori individuali. În el, Daniele Polencic, liderul proiectului, oferă un ghid vizual despre pașii care ar trebui urmați în caz de probleme generale cu aplicațiile rulante în clusterul K8s.

TL;DR: iată o diagramă care vă va ajuta să depanați deployment în Kubernetes:
Diagrama pentru identificarea și corectarea erorilor în cluster. Varianta originală (în engleză) este disponibilă în și .
Atunci când desfășurați o aplicație în Kubernetes, de obicei este necesar să definiți trei componente:
- Deployment — este o rețetă pentru crearea copiilor aplicației, numite pod-uri;
- Serviciu — un load balancer intern, care distribuie traficul între pod-uri;
- Ingress — o descriere a modului în care traficul va ajunge din lumea externă la Service.
Iată un rezumat grafic concis:
1) În Kubernetes, aplicațiile primesc trafic din exterior prin două straturi de load balancere: intern și extern.

2) Load balancer-ul intern se numește Service, cel extern - Ingress.

3) Deployment-ul creează pod-uri și le monitorizează (acestea nu sunt create manual).

Să presupunem că doriți să desfășurați o aplicație simplă de tipul Hello World. Configurația YAML pentru aceasta va arăta astfel:
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: /Definiția este destul de lungă și este ușor să te pierzi în modul în care componentele sunt legate între ele.
De exemplu:
- Când ar trebui să folosiți portul 80 și când - 8080?
- Ar trebui să creați un nou port pentru fiecare serviciu, pentru a nu intra în conflict?
- Au importanță numele etichetelor? Trebuie să fie aceleași peste tot?
Înainte de a ne concentra pe depanare, să ne reamintim cum sunt legate cele trei componente. Să începem cu Deployment și Service.
Legătura dintre Deployment și Service
Veți fi surprinși, dar Deployment-urile și Service-urile nu sunt legate între ele. În schimb, Service-ul indică direct către Pod-uri, fără a trece prin Deployment.
Astfel, ne interesează modul în care sunt corelate între ele Pod-urile și Service-urile. Trebuie să ținem cont de trei lucruri:
- Selector (
selector) al Service-ului trebuie să corespundă cel puțin unei etichete a Pod-ului. -
targetPorttrebuie să se potrivească cucontainerPortal containerului din Pod. -
portService-ul poate fi oricum. Diferite servicii pot folosi aceeași port, deoarece au adrese IP diferite.
Schema următoare prezintă tot ceea ce a fost menționat anterior într-o formă grafică:
1) Să presupunem că serviciul direcționează trafic către un pod:

2) La crearea pod-ului, este necesar să se stabilească containerPort pentru fiecare container din pod-uri:

3) La crearea serviciului trebuie să indicați port și targetPort. Dar prin care dintre acestea se face conectarea la container?

4) Prin targetPort. Acesta trebuie să se potrivească cu containerPort.

5) Să presupunem că în container este deschis portul 3000. Atunci valoarea targetPort trebuie să fie aceeași.

În fișierul YAML, etichetele și porturi / targetPort trebuie să corespundă:
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 # <<< Și ce zici de eticheta track: canary din partea de sus a secțiunii Deployment? Trebuie să se potrivească?
Această etichetă se referă la desfășurare și nu este folosită de serviciu pentru rutarea traficului. Cu alte cuvinte, poate fi ștearsă sau poate fi atribuită o altă valoare.
Dar ce zici de selectorul matchLabels?
Acesta trebuie întotdeauna să se potrivească cu etichetele Pod-ului, deoarece este folosit de Deployment pentru a urmări pod-urile.
Să presupunem că ai efectuat modificările corecte. Cum poți verifica?
Poți verifica etichetele pod-urilor folosind comanda următoare:
kubectl get pods --show-labelsSau, dacă pod-urile aparțin mai multor aplicații:
kubectl get pods --selector any-name=my-app --show-labels Unde any-name=my-app — aceasta este eticheta any-name: my-app.
A mai rămas vreo dificultate?
Se poate conecta la pod! Pentru asta trebuie folosită comanda port-forward în kubectl. Aceasta permite conectarea la serviciu și verificarea conexiunii.
kubectl port-forward service/<service name> 3000:80Aici:
-
service/<service name>— numele serviciului; în cazul nostru estemy-service; - 3000 — portul care trebuie să fie deschis pe computer;
- 80 — portul specificat în câmpul
portserviciului.
Dacă s-a reușit stabilirea conexiunii, atunci setările sunt corecte.
Dacă nu s-a reușit conectarea, atunci problema este cu etichetele sau porturile nu se potrivesc.
Conexiunea dintre Service și Ingress
Următorul pas în asigurarea accesului la aplicație este configurarea Ingress. Ingress trebuie să știe cum să găsească serviciul, apoi să găsească pod-urile și să le redirecționeze traficul. Ingress găsește serviciul dorit după nume și portul deschis.
În descrierea Ingress și Service trebuie să coincidă doi parametri:
-
servicePortîn Ingress trebuie să coincidă cu parametrulportîn Service; -
serviceNameîn Ingress trebuie să coincida cu câmpulnameîn Service.
Schema următoare rezumă conexiunea porturilor:
1) Așa cum știți deja, Service ascultă pe un anumit port:

2) Ingress are un parametru numit servicePort:

3) Acest parametru (servicePort) trebuie să coincidă întotdeauna cu port în definiția Service:

4) Dacă în Service este specificat portul 80, atunci este necesar ca servicePort să fie de asemenea 80:

În practică, trebuie să fie atenți la următoarele linii:
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: /Cum să verificați dacă Ingress funcționează?
Puteți utiliza metoda cu kubectl port-forward, dar în loc de serviciu trebuie să vă conectați la controlerul Ingress.
Mai întâi, trebuie să aflați numele pod-ului cu controlerul 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 Găsiți pod-ul Ingress (poate aparține unui alt spațiu de nume) și executați comanda describe, pentru a afla numerele porturilor:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPÎn cele din urmă, conectați-vă la pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemAcum, de fiecare dată când veți trimite o cerere pe portul 3000 pe computerul dvs., va fi redirecționată către portul 80 al pod-ului cu controlerul Ingress. Accesând , ar trebui să vedeți pagina generată de aplicație.
Rezumatul porturilor
Să ne amintim din nou care porturi și etichete trebuie să coincidă:
- Selectorul în definiția Service trebuie să coincidă cu eticheta pod-ului;
-
targetPortîn definiția Service trebuie să coincidă cucontainerPortcontainerul din interiorul pod-ului; -
portÎn definiția Service poate fi orice. Serviciile diferite pot folosi aceeași port, având adrese IP diferite; -
servicePortIngress-ului trebuie să corespundăportîn definiția Service; - Numele serviciului trebuie să corespundă cu câmpul
serviceNamedin Ingress.
Din păcate, nu este suficient să știi cum să structurezi corect configurația YAML.
Ce se întâmplă când ceva nu merge bine?
Este posibil ca podul să nu pornească sau să se blocheze.
3 pași pentru diagnosticarea problemelor aplicațiilor în Kubernetes
Înainte de a începe depanarea deploy-ului, trebuie să ai o bună înțelegere a modului în care funcționează Kubernetes.
Din moment ce fiecare aplicație rulată în K8s are trei componente, depanarea lor ar trebui să se facă într-o anumită ordine, începând cu partea de jos.
- Primul lucru de verificat este dacă podurile funcționează, apoi...
- Verifică dacă serviciul livrează trafic podurilor, apoi...
- Verifică dacă Ingress-ul este configurat corect.
Reprezentare vizuală:
1) Căutarea problemelor ar trebui să înceapă de jos. Începe prin a verifica dacă podurile au starea Gata și Running:

2) Dacă podurile sunt gata (Gata), trebuie să afli dacă serviciul distribuite traficul între poduri:

3) În cele din urmă, trebuie să analizezi legătura dintre serviciu și Ingress:

1. Diagnosticarea podurilor
În majoritatea cazurilor, problema este legată de pod. Asigură-te că podurile sunt marcate ca Gata și Running. Acest lucru se poate verifica cu comanda:
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 În rezultatul comenzii de mai sus, ultimul pod este marcat ca Running și Gata, dar acest lucru nu este cazul pentru celelalte două.
Cum să înțelegem că ceva nu a funcționat?
Există patru comenzi utile pentru diagnosticarea podurilor:
-
kubectl logspermite extragerea jurnalelor din containerele din pod; -
kubectl describe podpermet să vizualizezi lista evenimentelor legate de pod; -
kubectl get podpermite obținerea configurației YAML a podului stocate în Kubernetes; -
kubectl exec -ti bashpermite lansarea unei sesiuni interactive de terminal într-unul dintre containerele podului.
Pe care dintre ele să o alegi?
Problema este că nu există o comandă universală. Ar trebui să folosești o combinație a acestora.
Problemele tipice ale podurilor
Există două tipuri principale de erori ale podurilor: erori la pornire (startup) și erori în timpul execuției (runtime).
Erori de pornire:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
InvalidImageName
Erori de execuție:
-
CrashLoopBackOff -
RunContainerError -
KillContainerError -
VerifyNonRootError -
RunInitContainerError -
CreatePodSandboxError -
ConfigPodSandboxError -
KillPodSandboxError -
Unele erori apar mai frecvent decât altele. Iată câteva dintre cele mai comune erori și modalitățile de a le remedia. -
ImagePullBackOff
Această eroare apare atunci când Kubernetes nu poate obține imaginea pentru unul dintre containerele podului. Iată trei dintre cele mai comune motive pentru aceasta:
Numele imaginii este incorect specificat — de exemplu, ați făcut o greșeală în acesta sau imaginea nu există;
Un tag inexistent a fost specificat pentru imagine;
- Imaginea este stocată într-un registru privat, iar Kubernetes nu are permisiunea de a accesa acest registru.
- Primele două motive sunt ușor de remediat — pur și simplu corectați numele imaginii și tag-ul. În cazul ultimului, trebuie să adăugați acreditivele pentru registrul privat în Secret și să adăugați referințe la acesta în poduri. Documentația Kubernetes
- oferă un exemplu
de cum se poate face acest lucru. , dacă containerul nu se poate lansa. De obicei, acest lucru se întâmplă când:
CrashLoopBackOff
Există o eroare în aplicație care împiedică lansarea acesteia; CrashLoopBackOffeste configurat incorect
- Testul Liveness a eșuat prea multe ori.
- Container ;
- kubectl logs --previous
Aceasta va afișa mesajele de eroare din reincarnarea anterioară a containerului.
Această eroare apare atunci când containerul nu reușește să pornească. Aceasta corespunde momentului de dinaintea lansării aplicației. De obicei, cauza este o configurație greșită, cum ar fi:încercarea de a monta un volum inexistent, cum ar fi ConfigMap sau Secrets;
RunContainerError
încercarea de a monta un volum de tip read-only ca read-write.
- Pentru analiza acestor erori, comanda potrivită este
- kubectl describe pod
Podurile sunt în stare Pending După ce un pod este creat, rămâne în stare.
De ce se întâmplă acest lucru?
Iată posibilele cauze (presupun că scheduler-ul funcționează corect): Pending.
Nu sunt suficiente resurse în cluster, cum ar fi puterea de calcul și memoria, pentru a lansa podul.
În spațiul de nume corespunzător, a fost configurat un obiect
- ResourceQuota
- В соответствующем пространстве имен установлен объект
ResourceQuotaCrearea pod-ului va depăși cota spațiului de nume. - Pod-ul este marcat ca Pending
PersistentVolumeClaim.
În acest caz, se recomandă utilizarea comenzii kubectl describe și verificarea secțiunii Evenimente:
kubectl describe pod În cazul erorilor legate de ResourceQuotas, se recomandă să verificați log-urile cluster-ului folosind comanda
kubectl get events --sort-by=.metadata.creationTimestampPod-urile nu sunt în stare Ready
Dacă pod-ul este marcat ca Running, dar nu se află în stare Gata, înseamnă că verificarea pregătirii sale (readiness probe) a eșuat.
Când se întâmplă acest lucru, pod-ul nu se conectează la serviciu, iar traficul nu ajunge la el. Eșecul testului de readiness este cauzat de probleme în aplicație. În acest caz, pentru a găsi eroarea, trebuie să analizați secțiunea Evenimente în ieșirea comenzii kubectl describe.
2. Diagnosticarea serviciilor
Dacă pod-urile sunt marcate ca Running și Gata, dar nu există în continuare răspuns din partea aplicației, trebuie să verificați configurațiile serviciului.
Serviciile se ocupă de rutarea traficului către pod-uri în funcție de etichetele lor. Prin urmare, primul lucru care trebuie făcut este să verificați câte pod-uri sunt conectate la serviciu. Pentru asta, puteți verifica endpoint-urile din serviciu:
kubectl describe service | grep Endpoints Endpoint este o pereche de valori de tipul <IP-адрес:порт>, iar în output ar trebui să existe cel puțin o astfel de pereche (adică cu serviciul este conectat cel puțin un pod).
Dacă secțiunea Endpoints este goală, există două posibilități:
- nu există niciun pod cu eticheta corectă (sugestie: verificați dacă namespace-ul este corect ales);
- există o eroare în etichetele serviciului din selector.
Dacă vedeți o listă de endpoint-uri, dar totuși nu puteți accesa aplicația, atunci un vinovat probabil este o eroare în targetPort descrierea serviciului.
Cum să verificați funcționalitatea serviciului?
Indiferent de tipul serviciului, puteți utiliza comanda kubectl port-forward pentru a vă conecta la acesta:
kubectl port-forward service/ 3000:80Aici:
-
<service-name>— numele serviciului; - 3000 — portul pe care îl deschideți pe computer;
- 80 — portul pe partea serviciului.
3. Diagnosticarea Ingress
Dacă ați citit până aici, atunci:
- pod-urile sunt marcate ca
RunningșiGata; - serviciul distribuie cu succes traficul între pod-uri.
Totuși, nu puteți în continuare să accesați aplicația.
Acest lucru înseamnă că, cel mai probabil, controlerul Ingress este configurat greșit. Deoarece controlerul Ingress este un component terț în cluster, există diverse metode de depanare în funcție de tipul acestuia.
Dar înainte de a recurge la ajutorul uneltelor speciale pentru configurarea Ingress-ului, se poate face ceva foarte simplu. Ingress folosește serviceName și servicePort pentru a se conecta la serviciu. Este necesar să verificați dacă sunt configurate corect. Acest lucru se poate face cu ajutorul comenzii:
kubectl describe ingress Dacă coloana Backend este goală, este foarte probabil să existe o eroare în configurație. Dacă backend-urile sunt la locul lor, dar accesul la aplicație este totuși imposibil, problema ar putea fi legată de:
- setările de accesibilitate ale Ingress-ului din internetul public;
- setările de accesibilitate ale cluster-ului din internetul public.
Identificarea problemelor cu infrastructura se poate face conectându-vă direct la pod-ul Ingress-ului. Pentru asta, mai întâi găsiți pod-ul controlerului Ingress (poate fi în alt spațiu de nume):
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 Folosiți comanda describe, pentru a stabili portul:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep PortsÎn cele din urmă, conectați-vă la pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemAcum toate cererile pe portul 3000 de pe computer vor fi redirecționate către portul 80 al pod-ului.
Funcționează acum?
- Dacă da, atunci problema este cu infrastructura. Este necesar să se determine cum se face rutarea traficului în cluster.
- Dacă nu, atunci problema este cu controlerul Ingress.
Dacă nu reușiți să faceți controlerul Ingress să funcționeze, va trebui să-l depanați.
Există multe tipuri de controlere Ingress. Cele mai populare sunt Nginx, HAProxy, Traefik etc. (mai multe informații despre soluții existente găsiți în — nota trad.) Este indicat să consultați ghidul de soluționare a problemelor din documentația controlerului corespunzător. Deoarece este cel mai popular controler Ingress, am inclus în articol câteva sfaturi pentru a rezolva problemele asociate acestuia.
Depanarea controlerului Ingress Nginx
Proiectul Ingress-nginx are un . Comanda kubectl ingress-nginx poate fi folosită pentru:
- analiza log-urilor, backend-urilor, certificatelor etc.;
- conectarea la Ingress;
- studierea configurației curente.
Vor fi utile următoarele trei comenzi:
-
kubectl ingress-nginx lint— verificănginx.conf; -
kubectl ingress-nginx backend— investighează backend-ul (similar cukubectl describe ingress); -
kubectl ingress-nginx logs— verifică log-urile.
Rețineți: în unele cazuri poate fi necesar să specificați spațiul de nume corect pentru controlerul Ingress folosind flag-ul --namespace.
Rezumat
Diagnostica în Kubernetes poate fi o sarcină dificilă dacă nu știi de unde să începi. Problema ar trebui să fie abordată întotdeauna conform principiului „de jos în sus”: începe cu pod-urile, apoi treci la serviciu și Ingress. Metodele de depanare descrise în articol pot fi aplicate și altor obiecte, cum ar fi:
- Job-uri și CronJob-uri nefuncționale;
- StatefulSet-uri și DaemonSet-uri.
Doresc să îmi exprim recunoștința , și pentru observațiile și completările valoroase.
P.S. de la traducător
Citiți și în blogul nostru:
- «»;
- «»;
- «»;
- «».
Sursa: habr.com
