Заўв. перав.: Гэты артыкул уваходзіць у склад апублікаваных у свабодным доступе матэрыялаў праекта. , які навучае працы з Kubernetes кампаніі і індывідуальных адміністратараў. У ёй Daniele Polencic, кіраўнік праекта, дзеліцца нагляднай інструкцыяй аб тым, якія крокі варта рабіць у выпадку ўзнікнення праблем агульнага характару ў прыкладанняў, запушчаных у кластары K8s.

TL;DR: вось схема, якая дапаможа вам адладзіць deployment у Kubernetes:
Блок-схема для пошуку і выпраўленні памылак у кластары. У арыгінале (на англійскай) яна даступная ў и .
Пры разгортванні прыкладання ў Kubernetes звычайна неабходна вызначыць тры кампаненты:
- разгортванне - Гэта нейкі рэцэпт па стварэнні копій прыкладання, званых pod'амі;
- абслугоўванне - унутраны балансавальнік нагрузкі, размяркоўвалы трафік па pod'ах;
- Уваход - апісанне таго, як трафік будзе трапляць са знешняга свету да Service'у.
Вось кароткае графічнае рэзюмэ:
1) У Kubernetes прыкладанні атрымліваюць трафік з знешняга свету праз два пласта балансавальнікаў нагрузкі: унутраны і знешні.

2) Унутраны балансавальнік называецца Service, знешні - Ingress.

3) Deployment стварае pod'ы і сочыць за імі (яны не ствараюцца ўручную).

Выкажам здагадку, вы хочаце разгарнуць просценькі дадатак а-ля Прывітанне свет. YAML-канфігурацыя для яго будзе выглядаць наступным чынам:
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: /Вызначэнне даволі доўгае, і лёгка заблытацца ў тым, як кампаненты злучаны сябар з сябрам.
Напрыклад:
- Калі варта выкарыстоўваць порт 80, а калі - 8080?
- Ці варта ствараць новы порт для кожнага сэрвісу, каб яны не канфліктавалі?
- Ці маюць значэнні імёны лэйблаў? Ці павінны яны быць аднолькавымі ўсюды?
Перш чым засяродзіцца на адладцы, давайце ўспомнім, як тры кампаненты злучаны сябар з сябрам. Пачнём з Deployment і Service.
Сувязь Deployment'а і Service'а
Вы здзівіцеся, але Deployment'ы і Service'ы ніяк не злучаны. Замест гэтага Service напрамую паказвае на Pod'ы ў абыход Deployment'а.
Такім чынам, нас цікавіць, як звязаны адзін з адным Pod'ы і Service'ы. Варта памятаць тры рэчы:
- Селектар (
selector) у Service'а павінен адпавядаць хаця б аднаму лэйблу Pod'а. -
targetPortпавінен супадаць зcontainerPortкантэйнера ўнутры Pod'а. -
portService'а можа быць любым. Розныя сэрвісы могуць выкарыстоўваць адзін і той жа порт, паколькі ў іх розныя IP-адрасы.
Наступная схема прадстаўляе ўсё вышэйпералічанае ў графічнай форме:
1) Уявім, што сэрвіс накіроўвае трафік у нейкі pod:

2) Пры стварэнні pod'а неабходна задаць containerPort для кожнага кантэйнера ў pod'ах:

3) Пры стварэнні сэрвісу неабходна ўказаць port и targetPort. Але праз які з іх ідзе падлучэнне да кантэйнера?

4) Праз targetPort. Ён павінен супадаць з containerPort.

5) Дапусцім, у кантэйнеры адкрыты порт 3000. Тады значэнне targetPort павінна быць такім жа.

У YAML-файле лэйблы і ports / targetPort павінны супадаць:
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 # <<< А як наконт лэйбла track: canary у верхняй частцы падзелу Deployment? Ці павінен ён супадаць?
Гэты лэйбл адносіцца да разгортвання, і не выкарыстоўваецца сэрвісам для маршрутызацыі трафіку. Іншымі словамі, яго можна выдаліць ці прысвоіць іншае значэнне.
А што наконт селектара matchLabels?
Ён заўсёды павінен супадаць з лэйбламі Pod'а, паколькі выкарыстоўваецца Deployment'ам для адсочвання pod'аў.
Дапусцім, што вы ўнеслі правільныя праўкі. Як іх праверыць?
Праверыць лэйбл pod'аў можна наступнай камандай:
kubectl get pods --show-labelsЦі, калі pod'ы належаць некалькім прыкладанням:
kubectl get pods --selector any-name=my-app --show-labels Дзе any-name=my-app - гэта лэйбл any-name: my-app.
Засталіся цяжкасці?
Можна далучыцца да pod'у! Для гэтага трэба выкарыстоўваць каманду port-forward у kubectl. Яна дазваляе далучыцца да сэрвісу і праверыць злучэнне.
kubectl port-forward service/<service name> 3000:80Тут:
-
service/<service name>- імя сэрвісу; у нашым выпадку гэтаmy-service; - 3000 - порт, які патрабуецца адкрыць на кампутары;
- 80 - порт, прапісаны ў поле
portсэрвісу.
Калі ўдалося ўсталяваць злучэнне, значыць налады дакладныя.
Калі злучэнне ўсталяваць не атрымалася, значыць праблема з лэйбламі ці порты не супадаюць.
Сувязь Service'а і Ingress'а
Наступны крок у забеспячэнні доступу да дадатку звязаны з наладай Ingress'а. Ingress павінен ведаць, як адшукаць сервіс, затым знайсці pod'ы і накіраваць да іх трафік. Ingress знаходзіць патрэбны сэрвіс па імені і адкрытым порце.
У апісанні Ingress і Service павінны супадаць два параметры:
-
servicePortу Ingress павінен супадаць з параметрамportу Service; -
serviceNameу Ingress павінна супадаць з полемnameу Service.
Наступная схема падводзіць вынік па падлучэнні портаў:
1) Як вы ўжо ведаеце, Service слухае нейкі port:

2) У Ingress'а ёсць параметр, званы servicePort:

3) Гэты параметр (servicePort) заўсёды павінен супадаць з port у вызначэнні Service:

4) Калі ў Service зададзены порт 80, то неабходна, каб servicePort таксама быў роўны 80:

На практыцы неабходна зважаць на наступныя радкі:
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: /Як праверыць, ці працуе Ingress?
Можна скарыстацца метадам з kubectl port-forward, але замест сэрвісу трэба далучыцца да кантролера Ingress.
Спачатку трэба даведацца імя pod'а з кантролерам 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 Знайдзіце pod Ingress'а (ён можа ставіцца да іншай прасторы імёнаў) і выканайце каманду describe, каб даведацца нумары партоў:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep Ports
Ports: 80/TCP, 443/TCP, 18080/TCPНарэшце, падключыцеся да pod'у:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemЦяпер кожны раз, калі вы будзеце пасылаць запыт на порт 3000 на кампутары, ён будзе перанакіроўвацца на порт 80 pod'а з кантролерам Ingress. Перайшоўшы на , Вы павінны будзеце ўбачыць старонку, створаную дадаткам.
Рэзюмэ па партах
Давайце яшчэ раз успомнім аб тым, якія парты і лэйблы павінны супадаць:
- Селектар у вызначэнні Service павінен супадаць з лэйблам pod'а;
-
targetPortу вызначэнні Service павінен супадаць зcontainerPortкантэйнера ўнутры pod'а; -
portу вызначэнні Service можа быць любым. Розныя сэрвісы могуць выкарыстоўваць адзін і той жа порт, паколькі ў іх розныя IP-адрасы; -
servicePortIngress'а павінен супадаць зportу вызначэнні Service; - Назва сэрвісу павінна супадаць з полем
serviceNameу Ingress'е.
Нажаль, нядосыць ведаць, як правільна структураваць YAML-канфігурацыю.
Што здараецца, калі нешта ідзе не так?
Магчыма, pod не запускаецца ці ён падае.
3 кроку для дыягностыкі няспраўнасцяў у прыкладаннях у Kubernetes
Перш чым прыступаць да адладкі deployment'а, неабходна мець добрае ўяўленне аб тым, як працуе Kubernetes.
Паколькі ў кожным скачаным у K8s дадатку маюцца тры кампаненты, праводзіць іх адладку варта ў вызначаным парадку, пачынальна з самага нізу.
- Спачатку трэба пераканацца, што pod'ы працуюць, затым…
- Праверыць, ці пастаўляе сэрвіс трафік pod'ам, а потым…
- Праверыць, ці правільна наладжаны Ingress.
Візуальнае прадстаўленне:
1) Пачынаць пошук праблем варта з самага нізу. Перш праверце, што pod'ы маюць статуты Ready и Running:

2) Калі pod'ы гатовыя (Ready), варта высветліць, ці размяркоўвае сэрвіс трафік паміж pod'амі:

3) Нарэшце, трэба прааналізаваць сувязь сэрвісу і Ingress'а:

1. Дыягностыка pod'ов
У большасці выпадкаў праблема злучана з pod'ом. Пераканайцеся, што pod'ы значацца як Ready и Running. Праверыць гэта можна з дапамогай каманды:
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 У выснове каманды, прыведзенай вышэй, апошні pod значыцца як Running и Ready, Аднак для двух іншых гэта не так.
Як зразумець, што пайшло не так?
Ёсць чатыры карысныя каманды для дыягностыкі pod'аў:
-
kubectl logs <имя pod'а>дазваляе атрымаць логі з кантэйнераў у pod'е; -
kubectl describe pod <имя pod'а>дазваляе прагледзець спіс падзей, звязаных з pod'ом; -
kubectl get pod <имя pod'а>дазваляе атрымаць YAML-канфігурацыю pod'а, якая захоўваецца ў Kubernetes; -
kubectl exec -ti <имя pod'а> bashдазваляе запусціць інтэрактыўную камандную абалонку ў адным з кантэйнераў pod'а
Якую з іх абраць?
Справа ў тым, што няма ўніверсальнай каманды. Варта выкарыстоўваць іх камбінацыю.
Тыповыя праблемы pod'аў
Існуе два асноўных тыпу памылак pod'ов: памылкі падчас запуску (startup) і памылкі падчас працы (runtime).
Памылкі запуску:
-
ImagePullBackoff -
ImageInspectError -
ErrImagePull -
ErrImageNeverPull -
RegistryUnavailable -
InvalidImageName
Runtime-памылкі:
-
CrashLoopBackOff -
RunContainerError -
KillContainerError -
VerifyNonRootError -
RunInitContainerError -
CreatePodSandboxError -
ConfigPodSandboxError -
KillPodSandboxError -
SetupNetworkError -
TeardownNetworkError
Некаторыя памылкі сустракаюцца часцей за іншыя. Вось некалькі найболей распаўсюджаных памылак і спосабы іх ухілення.
ImagePullBackOff
Гэтая памылка з'яўляецца, калі Kubernetes не можа атрымаць выяву для аднаго з кантэйнераў pod'а. Вось тры самыя распаўсюджаныя прычыны гэтага:
- Няслушна паказана імя выявы - напрыклад, вы зрабілі ў ім памылку, ці выява не існуе;
- Пазначаны неіснуючы тэг для выявы;
- Выява захоўваецца ў зачыненым рэестры, і ў Kubernetes няма паўнамоцтваў для доступу да яго.
Першыя дзве прычыны ліквідаваць лёгка - дастаткова паправіць імя выявы і тэг. У выпадку апошняй неабходна занесці ўліковыя дадзеныя да зачыненага рэестру ў Secret і дадаць спасылкі на яго ў pod'ы. У дакументацыі Kubernetes таго, як гэта можна зрабіць.
CrashLoopBackOff
Kubenetes выводзіць памылку CrashLoopBackOff, калі кантэйнер не можа запусціцца. Звычайна такое здараецца, калі:
- У дадатку ёсць памылка, якая не дазваляе яго запусціць;
- кантэйнер ;
- Тэст Liveness завяршыўся няўдала занадта шмат разоў.
Неабходна паспрабаваць дабрацца да логаў з кантэйнера, каб высветліць прычыну яго збою. Калі атрымаць доступ да логаў цяжка, паколькі кантэйнер занадта хутка перазапускаецца, можна скарыстацца наступнай камандай:
kubectl logs <pod-name> --previousЯна выводзіць паведамленні аб памылках з папярэдняй рэінкарнацыі кантэйнера.
RunContainerError
Гэтая памылка ўзнікае, калі кантэйнер не ў стане запусціцца. Яна адпавядае моманту да запуску дадатку. Звычайна яе прычынай з'яўляецца няправільная настройка, напрыклад:
- спроба прымантаваць неіснуючы тым, такі як ConfigMap ці Secrets;
- спроба прымантаваць том тыпу read-only як read-write.
Для аналізу падобных памылак добра падыходзіць каманда. kubectl describe pod <pod-name>.
Pod'ы ў стане Pending
Пасля стварэння pod застаецца ў стане Pending.
Чаму такое адбываецца?
Вось магчымыя прычыны (я зыходжу са здагадкі, што планавальнік працуе нармальна):
- У кластары недастаткова рэсурсаў, такіх як вылічальная магутнасць і памяць, для запуску pod'а.
- У адпаведнай прасторы імёнаў усталяваны аб'ект
ResourceQuotaі стварэнне pod'а прывядзе да таго, што прастора імёнаў выйдзе за межы квоты. - Pod прывязаны да Pending
PersistentVolumeClaim.
У гэтым выпадку рэкамендуецца карыстацца камандай kubectl describe і праверыць раздзел Events:
kubectl describe pod <pod name> У выпадку памылак, звязаных з ResourceQuotas, рэкамендуецца прагледзець логі кластара з дапамогай каманды
kubectl get events --sort-by=.metadata.creationTimestampPod'ы не ў стане Ready
Калі pod значыцца як Running, але не знаходзіцца ў стане Ready, значыць праверка яго гатоўнасці (readiness probe) завяршаецца няўдала.
Калі такое адбываецца, pod не падлучаецца да сэрвісу, і трафік на яго не паступае. Збой тэсту readiness выкліканы праблемамі ў дадатку. У гэтым выпадку для пошуку памылкі неабходна прааналізаваць падзел Events у выснове каманды kubectl describe.
2. Дыягностыка сэрвісаў
Калі pod'ы значацца як Running и Ready, але адказу ад прыкладання па-ранейшаму няма, варта праверыць настройкі сэрвісу.
Сэрвісы займаюцца маршрутызацыяй трафіку да pod'аў у залежнасці ад іх лэйблаў. Таму першае, што трэба зрабіць - праверыць, колькі pod'аў працуюць з сэрвісам. Для гэтага можна праверыць endpoint'ы ў сэрвісе:
kubectl describe service <service-name> | grep Endpoints Endpoint - гэта пара значэнняў выгляду <IP-адрес:порт>, і ў выснове павінна прысутнічаць хаця б адна такая пара (гэта значыць з сэрвісам працуе хаця б адзін pod).
Калі раздзел Endpoins пусты, магчымыя два варыянты:
- няма ніводнага pod'а з правільным лэйблам (падказка: праверце, ці правільна абраны namespace);
- ёсць памылка ў лэйблах сэрвісу ў селектары.
Калі вы бачыце спіс endpoint'аў, але па-ранейшаму не можаце атрымаць доступ да дадатку, то верагодным вінаватым з'яўляецца памылка ў targetPort у апісанні сэрвісу.
Як праверыць працаздольнасць сэрвісу?
Незалежна ад тыпу сэрвісу, можна выкарыстоўваць каманду kubectl port-forward для падлучэння да яго:
kubectl port-forward service/<service-name> 3000:80Тут:
-
<service-name>- імя сэрвісу; - 3000 - порт, які вы адкрываеце на кампутары;
- 80 - порт на баку сэрвісу.
3. Дыягностыка Ingress
Калі вы дачыталі да гэтага месца, то:
- pod'ы значацца як
RunningиReady; - сэрвіс паспяхова размяркоўвае трафік па pod'ах.
Аднак вы па-ранейшаму не можаце дастукацца да прыкладання.
Гэта азначае, што, хутчэй за ўсё, няправільна настроены кантролер Ingress. Паколькі кантролер Ingress з'яўляецца іншым кампанентам у кластары, існуюць розныя метады адладкі ў залежнасці ад яго тыпу.
Але перш чым звярнуцца да дапамогі адмысловых прылад для налады Ingress'а, можна зрабіць нешта зусім простае. Ingress выкарыстоўвае serviceName и servicePort для падлучэння да сэрвісу. Неабходна праверыць, ці правільна яны настроены. Зрабіць гэта можна з дапамогай каманды:
kubectl describe ingress <ingress-name> Калі слупок Backend пусты, высокая верагоднасць памылкі ў канфігурацыі. Калі бэкэнды на месцы, але доступу да дадатку па-ранейшаму няма, то праблема можа быць звязана з:
- настройкамі даступнасці Ingress'а з публічнага інтэрнэту;
- настройкамі даступнасці кластара з публічнага інтэрнэту.
Выявіць праблемы з інфраструктурай можна, падлучыўшыся напрамую да pod'у Ingress'а. Для гэтага спачатку знайдзіце pod 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 Скарыстайцеся камандай describe, каб усталяваць порт:
kubectl describe pod nginx-ingress-controller-6fc5bcc
--namespace kube-system
| grep PortsНарэшце, падключыцеся да pod'у:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-systemЦяпер усе запыты на порт 3000 на кампутары будуць перанакіроўвацца на порт 80 pod'а.
Ці працуе ён зараз?
- Калі так, то праблема з інфраструктурай. Неабходна высветліць, як менавіта ажыццяўляецца маршрутызацыя трафіку ў кластар.
- Калі не, то праблема з кантролерам Ingress.
Калі не атрымліваецца прымусіць працаваць кантролер Ingress, давядзецца правесці яго адладку.
Існуе шмат разнавіднасцяў кантролераў Ingress. Самымі папулярнымі з'яўляюцца Nginx, HAProxy, Traefik і інш. (падрабязней аб існуючых рашэннях гл. - заўв. перав.) Варта скарыстацца кіраўніцтвам па ўхіленні непаладак у дакументацыі які адпавядае кантролера. Паколькі з'яўляецца самым папулярным кантролерам Ingress, мы ўключылі ў артыкул некалькі парад па рашэнні звязаных з ім праблем.
Адладка кантролера Ingress Nginx
У праекту Ingress-nginx маецца афіцыйны . Каманду kubectl ingress-nginx можна выкарыстоўваць для:
- аналізу логаў, бэкэндаў, сертыфікатаў і г.д.;
- падлучэння да Ingress'у;
- вывучэння бягучай канфігурацыі.
Дапамогуць вам у гэтым наступныя тры каманды:
-
kubectl ingress-nginx lint- правяраеnginx.conf; -
kubectl ingress-nginx backend- даследуе бэкэнд (па аналогіі зkubectl describe ingress <ingress-name>); -
kubectl ingress-nginx logs- правярае логі.
Звярніце ўвагу: у некаторых выпадках можа спатрэбіцца пазначыць правільную прастору імёнаў для кантролера Ingress з дапамогай сцяга --namespace <name>.
Рэзюмэ
Дыягностыка ў Kubernetes можа аказацца няпростай задачай, калі не ведаць, з чаго пачаць. Да праблемы заўсёды варта падыходзіць па прынцыпе "знізу-уверх": пачынайце з pod'ов, а затым пераходзіце да сэрвісу і Ingress'у. Метады адладкі, апісаныя ў артыкуле, могуць прымяняцца і да іншых аб'ектаў, такім як:
- непрацуючыя Job'ы і CronJob'ы;
- StatefulSet'ы і DaemonSet'ы.
Выказваю падзяку , и за каштоўныя заўвагі і дапаўненні.
PS ад перакладчыка
Чытайце таксама ў нашым блогу:
- «»;
- «»;
- «»;
- «.
Крыніца: habr.com
