10 често срещани грешки в Kubernetes

Забележка. превод: Авторите на тази статия са инженери от малка чешка фирма pipetail. Те успяха да съставят прекрасен списък от [понякога банални, но все пак] много належащи проблеми и погрешни схващания, свързани с работата на клъстерите Kubernetes.

10 често срещани грешки в Kubernetes

През годините на използване на Kubernetes сме работили с голям брой клъстери (както управлявани, така и неуправлявани - на GCP, AWS и Azure). С течение на времето започнахме да забелязваме, че някои грешки постоянно се повтарят. В това обаче няма нищо срамно: повечето от тях сме направили сами!

Статията съдържа най-често срещаните грешки и също така споменава как да ги коригирате.

1. Ресурси: искания и ограничения

Този артикул определено заслужава най-голямо внимание и първо място в списъка.

CPU заявка обикновено или изобщо не е посочено, или има много ниска стойност (за да поставите възможно най-много подове на всеки възел). Така възлите се претоварват. По време на високо натоварване мощността за обработка на възела се използва напълно и определено работно натоварване получава само това, което е „искано“ от Дроселиране на процесора. Това води до увеличено забавяне на приложението, изчакване и други неприятни последици. (Прочетете повече за това в другия ни скорошен превод: „Ограничения на процесора и агресивно дроселиране в Kubernetes“- прибл. превод)

Най-доброто усилие (изключително не препоръчително):

resources: {}

Изключително ниско натоварване на процесора (изключително не препоръчително):

   resources:
      Requests:
        cpu: "1m"

От друга страна, наличието на лимит на процесора може да доведе до необосновано пропускане на часовникови цикли от модули, дори ако процесорът на възела не е напълно зареден. Отново това може да доведе до увеличени закъснения. Споровете около параметъра продължават CPU квота CFS в Linux ядрото и CPU throttling в зависимост от зададените лимити, както и деактивиране на квотата на CFS... Уви, CPU лимитите могат да причинят повече проблеми, отколкото могат да разрешат. Повече информация за това можете да намерите на връзката по-долу.

Прекомерна селекция (прекален ангажимент) проблемите с паметта могат да доведат до по-големи проблеми. Достигането на лимита на процесора води до пропускане на часовникови цикли, докато достигането до лимита на паметта води до убиване на под. Наблюдавали ли сте някога OOMkill? Да, точно за това говорим.

Искате ли да сведете до минимум вероятността това да се случи? Не разпределяйте прекалено много памет и използвайте Гарантирано QoS (Качество на услугата), като настроите заявката за памет на ограничението (както в примера по-долу). Прочетете повече за това в Презентации на Хенинг Джейкъбс (Водещ инженер в Zalando).

Разрушим (по-голям шанс да бъдете убит от OOM):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

Гарантирано:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

Какво потенциално ще помогне при настройването на ресурси?

С metrics-сървър можете да видите текущото потребление на ресурси на процесора и използването на паметта от подове (и контейнери в тях). Най-вероятно вече го използвате. Просто изпълнете следните команди:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

Те обаче показват само текущото използване. Може да ви даде груба представа за порядъка на величината, но в крайна сметка ще ви трябва история на промените в показателите във времето (за да отговорите на въпроси като: „Какво беше пиковото натоварване на процесора?“, „Какво беше натоварването вчера сутринта?“ и т.н.). За това можете да използвате Прометей, DataDog и други инструменти. Те просто получават показатели от metrics-сървър и ги съхраняват, а потребителят може да ги запитва и да ги начертае съответно.

VerticalPodAutoscaler Тя позволява на автоматизирайте този процес. Той проследява историята на използването на процесора и паметта и задава нови заявки и ограничения въз основа на тази информация.

Ефективното използване на изчислителната мощност не е лесна задача. Все едно играеш тетрис през цялото време. Ако плащате твърде много за изчислителна мощност с ниска средна консумация (да речем ~10%), препоръчваме ви да разгледате продукти, базирани на AWS Fargate или Virtual Kubelet. Те са изградени върху модел на таксуване без сървър/плащане при използване, което може да се окаже по-евтино при такива условия.

2. Сонди за жизненост и готовност

По подразбиране проверките за жизнеспособност и готовност не са активирани в Kubernetes. И понякога забравят да ги включат...

Но как иначе можете да инициирате рестартиране на услугата в случай на фатална грешка? И как балансьорът на натоварването знае, че под е готов да приеме трафик? Или че може да поеме повече трафик?

Тези тестове често се бъркат един с друг:

  • Жизненост — проверка за „оцеляване“, която рестартира модула, ако не успее;
  • Готовност — проверка на готовността, ако не успее, прекъсва връзката на pod от услугата Kubernetes (това може да се провери с kubectl get endpoints) и трафикът не достига до него, докато следващата проверка не приключи успешно.

И двете проверки ИЗВЪРШВА СЕ ПРЕЗ ЦЕЛИЯ ЖИЗНЕН ЦИКЪЛ НА ПОД. Много е важно.

Често срещано погрешно схващане е, че сондите за готовност се изпълняват само при стартиране, така че балансьорът да знае, че капсулата е готова (Ready) и може да започне да обработва трафик. Това обаче е само един от вариантите за тяхното използване.

Друга е възможността да разберете, че трафикът на подс е прекомерен и го претоварва (или подът извършва ресурсоемки изчисления). В този случай проверката на готовността помага намалете натоварването на капсулата и я „охладете“.. Успешното завършване на проверка на готовността в бъдеще позволява увеличете отново натоварването на капсулата. В този случай (ако тестът за готовност е неуспешен), неуспехът на теста за жизненост би бил много контрапродуктивен. Защо да рестартирате под, който е здрав и работи здраво?

Следователно в някои случаи е по-добре да няма никакви проверки, отколкото да ги активирате с неправилно конфигурирани параметри. Както беше посочено по-горе, ако проверка на жизнеспособността проверка на готовността на копията, значи си в голяма беда. Възможен вариант е конфигуриране само тест за готовностИ опасна жизненост оставете настрана.

И двата типа проверки не трябва да се провалят, когато общите зависимости се провалят, в противен случай това ще доведе до каскаден (лавинен) отказ на всички подове. С други думи, не се наранявайте.

3. LoadBalancer за всяка HTTP услуга

Най-вероятно имате HTTP услуги във вашия клъстер, които искате да препратите към външния свят.

Ако отворите услугата като type: LoadBalancer, неговият контролер (в зависимост от доставчика на услуги) ще предостави и договори външен LoadBalancer (не е задължително да работи на L7, а по-скоро дори на L4) и това може да повлияе на цената (външен статичен IPv4 адрес, изчислителна мощност, таксуване на секунда ) поради необходимостта от създаване на голям брой такива ресурси.

В този случай е много по-логично да използвате един външен балансьор на натоварването, отваряйки услуги като type: NodePort. Или още по-добре, разширете нещо подобно nginx-ingress-controller (Or траефик), който ще бъде единственият NodePort крайна точка, свързана с външния балансьор на натоварването и ще маршрутизира трафика в клъстера, използвайки навлизане- Ресурси на Kubernetes.

Други вътрешноклъстерни (микро)услуги, които взаимодействат помежду си, могат да „комуникират“, използвайки услуги като ClusterIP и вграден механизъм за откриване на услуги чрез DNS. Просто не използвайте техния публичен DNS/IP, тъй като това може да повлияе на забавянето и да увеличи цената на облачните услуги.

4. Автоматично мащабиране на клъстер без отчитане на неговите характеристики

Когато добавяте възли към и ги премахвате от клъстер, не трябва да разчитате на някои основни показатели като използването на процесора на тези възли. Планирането на под трябва да вземе предвид много ограничения, като афинитет на под/възел, петна и толеранси, заявки за ресурси, QoS и др. Използването на външен автоскалер, който не взема предвид тези нюанси, може да доведе до проблеми.

Представете си, че определен под трябва да бъде планиран, но цялата налична мощност на процесора е поискана/разглобена и подът засяда в състояние Pending. Външният автоматичен скалер вижда средното текущо натоварване на процесора (не заявеното) и не инициира разширение (мащабирано) - не добавя друг възел. В резултат на това тази група няма да бъде планирана.

В този случай, обратно мащабиране (мащабиране) — премахването на възел от клъстер винаги е по-трудно за изпълнение. Представете си, че имате под със състояние (със свързано постоянно хранилище). Постоянни обеми обикновено принадлежат на специфична зона на достъпност и не се репликират в региона. По този начин, ако външен инструмент за автоматично мащабиране изтрие възел с този pod, планировчикът няма да може да планира този pod на друг възел, тъй като това може да се направи само в зоната на достъпност, където се намира постоянното хранилище. Pod ще остане в състояние Pending.

Много популярен в общността на Kubernetes cluster-autoscaler. Той работи на клъстер, поддържа API от големи облачни доставчици, взема предвид всички ограничения и може да мащабира в горните случаи. Също така е в състояние да се мащабира, като същевременно поддържа всички зададени ограничения, като по този начин спестява пари (които иначе биха били похарчени за неизползван капацитет).

5. Пренебрегване на възможностите на IAM/RBAC

Пазете се от използването на IAM потребители с постоянни тайни за машини и приложения. Организирайте временен достъп с помощта на роли и акаунти за услуги (сервизни сметки).

Често се сблъскваме с факта, че ключовете за достъп (и тайните) са твърдо кодирани в конфигурацията на приложението, както и пренебрегването на ротацията на тайните, въпреки че имаме достъп до Cloud IAM. Използвайте IAM роли и акаунти за услуги вместо потребители, където е подходящо.

10 често срещани грешки в Kubernetes

Забравете за kube2iam и отидете направо към IAM роли за акаунти за услуги (както е описано в бележка със същото име Щепан Врани):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

Една анотация. Не е толкова трудно, нали?

Освен това не предоставяйте привилегии на акаунти за услуги и потребителски профили admin и cluster-adminако не им трябва. Това е малко по-трудно за изпълнение, особено в RBAC K8s, но определено си заслужава усилието.

6. Не разчитайте на автоматичен анти-афинитет за подс

Представете си, че имате три реплики на някакво внедряване на възел. Възелът пада, а заедно с него и всички реплики. Неприятна ситуация, нали? Но защо всички реплики бяха на един и същи възел? Kubernetes не трябва ли да осигурява висока достъпност (HA)?!

За съжаление, планировчикът на Kubernetes по своя собствена инициатива не спазва правилата за отделно съществуване (анти-афинитет) за подс. Те трябва да бъдат изрично посочени:

// опущено для краткости
      labels:
        app: zk
// опущено для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

Това е всичко. Сега подовете ще бъдат планирани на различни възли (това условие се проверява само по време на планиране, но не и по време на тяхната работа - следователно requiredDuringSchedulingIgnoredDuringExecution).

Тук говорим за podAntiAffinity на различни възли: topologyKey: "kubernetes.io/hostname", - а не за различни зони на достъпност. За да внедрите пълноценна HA, ще трябва да се задълбочите в тази тема.

7. Игнориране на PodDisruptionBudgets

Представете си, че имате производствено натоварване на Kubernetes клъстер. Периодично възлите и самият клъстер трябва да бъдат актуализирани (или изведени от експлоатация). PodDisruptionBudget (PDB) е нещо като споразумение за гаранция на услугата между администраторите на клъстера и потребителите.

PDB ви позволява да избегнете прекъсвания на услугата, причинени от липса на възли:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

В този пример вие, като потребител на клъстера, заявявате на администраторите: „Хей, имам услуга за пазач на зоологическа градина и каквото и да правите, бих искал да имам винаги налични поне 2 копия на тази услуга.“

Можете да прочетете повече за това тук.

8. Множество потребители или среди в общ клъстер

Пространства от имена на Kubernetes (именни пространства) не осигуряват силна изолация.

Често срещано погрешно схващане е, че ако внедрите непроизводствено зареждане в едно пространство от имена и продукционно зареждане в друго, тогава те няма да си влияят по никакъв начин... Въпреки това, определено ниво на изолация може да бъде постигнато чрез използване на заявки/ограничения за ресурси, задаване на квоти и задаване на priorityClasses. Известна „физическа“ изолация в равнината на данните се осигурява от афинитети, толерантности, петна (или селектори на възли), но такова разделяне е доста труден изпълнявам.

Тези, които трябва да комбинират двата вида натоварвания в един и същ клъстер, ще трябва да се справят със сложността. Ако няма такава нужда и можете да си позволите да имате такъв още един клъстер (да речем в публичен облак), тогава е по-добре да го направите. Така ще се постигне много по-високо ниво на изолация.

9. externalTrafficPolicy: Клъстер

Много често наблюдаваме, че целият трафик вътре в клъстера идва през услуга като NodePort, за която е зададена политиката по подразбиране externalTrafficPolicy: Cluster... Означава, че NodePort е отворен на всеки възел в клъстера и можете да използвате всеки от тях, за да взаимодействате с желаната услуга (набор от подове).

10 често срещани грешки в Kubernetes

В същото време реални подове, свързани с гореспоменатата услуга NodePort, обикновено са достъпни само на определен подмножество от тези възли. С други думи, ако се свържа с възел, който няма необходимия pod, той ще пренасочи трафик към друг възел, добавяне на хоп и увеличаване на латентността (ако възлите са разположени в различни зони на достъпност/центрове за данни, латентността може да бъде доста висока; в допълнение, разходите за изходящ трафик ще се увеличат).

От друга страна, ако определена услуга на Kubernetes има зададена политика externalTrafficPolicy: Local, тогава NodePort се отваря само на тези възли, където действително се изпълняват необходимите подове. Когато използвате външен балансьор на натоварването, който проверява състоянието (здравна проверка) крайни точки (как става AWS ELB), Той ще изпрати трафик само до необходимите възли, което ще има благоприятен ефект върху закъсненията, компютърните нужди, изходните сметки (и здравият разум диктува същото).

Има голяма вероятност вече да използвате нещо подобно траефик или nginx-ingress-controller като крайна точка на NodePort (или LoadBalancer, който също използва NodePort) за маршрутизиране на входящ HTTP трафик и настройването на тази опция може значително да намали забавянето за такива заявки.

В тази публикация Можете да научите повече за externalTrafficPolicy, нейните предимства и недостатъци.

10. Не се обвързвайте с клъстери и не злоупотребявайте с контролната равнина

Преди това беше обичайно сървърите да се обаждат с правилни имена: Антон, HAL9000 и Colossus... Днес те са заменени от произволно генерирани идентификатори. Въпреки това навикът остана и сега собствените имена отиват в клъстери.

Типична история (базирана на реални събития): всичко започна с доказателство за концепцията, така че клъстерът имаше гордо име тестване… Минаха години и ВСЕ ОЩЕ се използва в производството и всеки се страхува да го докосне.

Няма нищо забавно в това, че клъстерите се превръщат в домашни любимци, затова препоръчваме да ги премахвате периодично, докато тренирате възстановяване след бедствие (това ще помогне инженерство на хаоса - прибл. превод). Освен това няма да навреди да работите върху контролния слой (контролен самолет). Да се ​​страхувате да го докоснете не е добър знак. и т.н. мъртъв? Момчета, наистина сте в беда!

От друга страна, не трябва да се увличате от манипулирането му. С време контролният слой може да стане бавен. Най-вероятно това се дължи на голям брой обекти, създадени без тяхната ротация (често срещана ситуация при използване на Helm с настройки по подразбиране, поради което състоянието му в configmaps/secrets не се актуализира - в резултат на това хиляди обекти се натрупват в контролния слой) или с постоянно редактиране на kube-api обекти (за автоматично мащабиране, за CI/CD, за наблюдение, регистрационни файлове на събития, контролери и др.).

Освен това препоръчваме да проверите споразуменията SLA/SLO с управлявания доставчик на Kubernetes и да обърнете внимание на гаранциите. Продавачът може да гарантира наличност на контролния слой (или неговите подкомпоненти), но не и p99 забавянето на заявките, които изпращате до него. С други думи, можете да влезете kubectl get nodes, и да получите отговор само след 10 минути и това няма да е нарушение на условията на споразумението за услуга.

11. Бонус: използване на най-новия етикет

Но това вече е класика. Напоследък срещаме тази техника по-рядко, тъй като мнозина, поучени от горчив опит, са спрели да използват маркера :latest и започна да закача версии. Ура!

ECR поддържа неизменност на таговете за изображения; Препоръчваме ви да се запознаете с тази забележителна функция.

Обобщение

Не очаквайте всичко да работи за една нощ: Kubernetes не е панацея. Лошо приложение ще остане по този начин дори в Kubernetes (и вероятно ще стане по-лошо). Невниманието ще доведе до прекомерна сложност, бавна и напрегната работа на контролния слой. Освен това рискувате да останете без стратегия за възстановяване след бедствие. Не очаквайте Kubernetes да осигури изолация и висока наличност веднага. Прекарайте известно време, за да направите приложението си наистина родно в облак.

Можете да се запознаете с неуспешния опит на различни отбори в този сборник с разкази от Хенинг Джейкъбс.

Тези, които желаят да добавят към списъка с грешки, даден в тази статия, могат да се свържат с нас в Twitter (@MarekBartik, @MstrsObserver).

PS от преводача

Прочетете също в нашия блог:

Източник: www.habr.com

Добавяне на нов коментар