Пет промашувања при распоредување на првата апликација на Kubernetes

Пет промашувања при распоредување на првата апликација на KubernetesНеуспех од Арис Дример

Многу луѓе мислат дека е доволно да ја префрлите апликацијата на Kubernetes (или користејќи Helm или рачно) - и ќе има среќа. Но, не е сè толку едноставно.

Тим Mail.ru Cloud Solutions преведе статија од инженерот DevOps Џулијан Гинди. Тој кажува со какви стапици се соочила неговата компанија за време на процесот на миграција за да не стапнеш на истото гребло.

Чекор еден: Поставете барања и ограничувања за Pod

Да почнеме со поставување чиста средина во која ќе работат нашите мешунки. Kubernetes е одличен при распоред и неуспех. Но, се покажа дека распоредувачот понекогаш не може да постави подлога ако е тешко да се процени колку ресурси му се потребни за успешно да работи. Ова е местото каде што се појавуваат барања за ресурси и ограничувања. Има многу дебати за најдобриот пристап за поставување барања и ограничувања. Понекогаш се чини дека ова е навистина повеќе уметност отколку наука. Еве го нашиот пристап.

Барања за под е главната вредност што ја користи распоредувачот за оптимално поставување на подлогата.

На Кубернетес документација: Чекорот за филтрирање дефинира збир на јазли каде што може да се закаже Pod. На пример, филтерот PodFitsResources проверува дали некој јазол има доволно ресурси за да задоволи одредени барања за ресурси од подлогата.

Ние ги користиме барањата за апликации на таков начин што можеме да процениме колку ресурси всушност Апликацијата треба да функционира правилно. На овој начин распоредувачот може реално да ги постави јазлите. Првично, сакавме да ги презакажуваме барањата за да обезбедиме доволно ресурси за секој Pod, но забележавме дека времето за закажување значително се зголеми, а некои Pod не беа целосно закажани, како да нема барања за ресурси за нив.

Во овој случај, распоредувачот често ќе ги „исцеди“ подлогите и нема да може да ги презакаже бидејќи контролната рамнина немаше поим колку ресурси ќе и требаат на апликацијата, што е клучна компонента на алгоритмот за закажување.

Граници на под е појасна граница за мешунка. Тој го претставува максималниот износ на ресурси што кластерот ќе ги додели на контејнерот.

Повторно, од официјална документација: Ако контејнер има ограничување на меморијата од 4 GiB, тогаш кубелетот (и времето на работа на контејнерот) ќе го наметнат. Времето на траење спречува контејнерот да користи повеќе од наведеното ограничување на ресурсите. На пример, кога процес во контејнер се обидува да користи повеќе од дозволеното количество меморија, системското јадро го завршува процесот со грешка „надвор од меморија“ (OOM).

Контејнер секогаш може да користи повеќе ресурси отколку што е наведено барањето за ресурси, но никогаш не може да користи повеќе од лимитот. Оваа вредност е тешко да се постави правилно, но е многу важна.

Идеално, сакаме барањата за ресурси на pod да се менуваат во текот на животниот циклус на процесот без да се мешаат со други процеси во системот - ова е целта на поставувањето ограничувања.

За жал, не можам да дадам конкретни упатства за тоа кои вредности да ги поставам, но ние самите се придржуваме до следниве правила:

  1. Користејќи алатка за тестирање на оптоварување, симулираме основно ниво на сообраќај и ја набљудуваме употребата на ресурсите на под (меморија и процесор).
  2. Поставете ги барањата за подлоги на произволно ниска вредност (со ограничување на ресурсите од околу 5 пати поголема од вредноста на барањата) и набљудувајте. Кога барањата се на премногу ниско ниво, процесот не може да започне, што често предизвикува криптични грешки за извршување на Go.

Забележувам дека повисоките ограничувања на ресурсите го отежнуваат распоредот бидејќи на pod му треба целен јазол со доволно достапни ресурси.

Замислете ситуација кога имате лесен веб-сервер со многу високо ограничување на ресурсите, како 4 GB меморија. Овој процес најверојатно ќе треба да се намали хоризонтално и секој нов подлог ќе треба да се закаже на јазол со најмалку 4 GB достапна меморија. Ако не постои таков јазол, кластерот мора да воведе нов јазол за обработка на оваа подлога, што може да потрае некое време. Важно е да се постигне минимална разлика помеѓу барањата за ресурси и ограничувањата за да се обезбеди брзо и непречено скалирање.

Чекор два: Поставете тестови за живост и подготвеност

Ова е уште една суптилна тема за која често се дискутира во заедницата Кубернет. Важно е да се има добро разбирање на тестовите за живост и подготвеност бидејќи тие обезбедуваат механизам за стабилно функционирање на софтверот и го минимизираат времето на застој. Сепак, тие можат сериозно да влијаат на перформансите на вашата апликација доколку не се правилно конфигурирани. Подолу е резиме на тоа што се двата примероци.

Nessивост покажува дали контејнерот работи. Ако не успее, кубелетот го убива контејнерот и политиката за рестартирање е овозможена за него. Ако контејнерот не е опремен со Liveness Probe, тогаш стандардната состојба ќе биде успешна - како што е наведено во Кубернетес документација.

Сондите Liveness треба да бидат евтини, односно да не трошат многу ресурси, бидејќи тие работат често и треба да го информираат Kubernetes дека апликацијата работи.

Ако ја поставите опцијата да се извршува секоја секунда, ова ќе додаде 1 барање во секунда, затоа имајте предвид дека ќе бидат потребни дополнителни ресурси за обработка на овој сообраќај.

Во нашата компанија, Liveness тестовите ги тестираат основните компоненти на апликацијата, дури и ако податоците (на пример, од далечинска база на податоци или кеш) не се целосно достапни.

Поставивме крајна точка за „здравје“ во апликациите што едноставно враќа код за одговор од 200. Ова е индикатор дека процесот работи и може да се справи со барањата (но сè уште не сообраќајот).

Пример Готовност покажува дали контејнерот е подготвен да опслужува барања. Ако сондата за подготвеност не успее, контролорот на крајната точка ја отстранува IP адресата на подлогата од крајните точки на сите услуги што се совпаѓаат со подлогата. Ова е наведено и во документацијата на Кубернетес.

Сондите за подготвеност трошат повеќе ресурси, бидејќи тие мора да го погодат задниот дел на таков начин што ќе покажат дека апликацијата е подготвена да прифаќа барања.

Во заедницата има многу дебати за тоа дали директно да се пристапи до базата на податоци. Со оглед на горните трошоци (проверките се чести, но може да се контролираат), решивме дека за некои апликации подготвеноста за опслужување на сообраќајот се брои само откако ќе провериме дали записите се враќаат од базата на податоци. Добро дизајнираните тестови за подготвеност обезбедија повисоки нивоа на достапност и го елиминираа времето на застој за време на распоредувањето.

Ако одлучите да ја побарате базата на податоци за да ја тестирате подготвеноста на вашата апликација, проверете дали е што е можно поевтина. Да го земеме ова прашање:

SELECT small_item FROM table LIMIT 1

Еве пример за тоа како ги конфигурираме овие две вредности во Kubernetes:

livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2

Можете да додадете некои дополнителни опции за конфигурација:

  • initialDelaySeconds - колку секунди ќе поминат помеѓу лансирањето на контејнерот и почетокот на лансирањето на сондите.
  • periodSeconds - интервал на чекање помеѓу примероците.
  • timeoutSeconds — бројот на секунди по кои лопатката се смета за итна. Нормален тајмаут.
  • failureThreshold е бројот на неуспеси на тестот пред да се испрати сигнал за рестартирање до подлогата.
  • successThreshold е бројот на успешни обиди пред подлогата да премине во подготвена состојба (по неуспех кога подлогата ќе се стартува или ќе се опорави).

Чекор три: Поставување на стандардните мрежни политики на Pod

Kubernetes има „рамна“ мрежна топографија, по дифолт сите подлоги директно комуницираат едни со други. Во некои случаи тоа не е пожелно.

Потенцијален безбедносен проблем е тоа што напаѓачот може да користи една ранлива апликација за да испрати сообраќај до сите подлоги на мрежата. Како и во многу области на безбедност, овде важи принципот на најмала привилегија. Идеално, мрежните политики треба експлицитно да наведат кои врски помеѓу подлоги се дозволени, а кои не се дозволени.

На пример, следново е едноставна политика која го негира целиот дојдовен сообраќај за одреден именски простор:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress

Визуелизација на оваа конфигурација:

Пет промашувања при распоредување на првата апликација на Kubernetes
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Повеќе детали тука.

Чекор четири: Прилагодено однесување со куки и контејнери за иницирање

Една од нашите главни цели беше да обезбедиме распоредувања во Kubernetes без прекини за програмерите. Ова е тешко бидејќи има многу опции за исклучување на апликациите и ослободување на нивните искористени ресурси.

Посебни тешкотии се појавија со Nginx. Забележавме дека при распоредување на овие Pods во низа, активните врски беа прекинати пред успешно да се завршат.

По детално истражување на Интернет, се покажа дека Kubernetes не чека Nginx конекциите да се исцрпат пред да го затворат подот. Со помош на куката за пред-стоп, ја имплементиравме следната функционалност и целосно се ослободивме од застојот:

lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]

Но nginx-killer.sh:

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done

Друга исклучително корисна парадигма е употребата на init контејнери за справување со лансирањето на специфични апликации. Ова е особено корисно ако имате процес на миграција на базата на податоци со интензивен ресурси, кој мора да се изврши пред да започне апликацијата. Можете исто така да наведете повисоко ограничување на ресурсите за овој процес без да поставите такво ограничување за главната апликација.

Друга вообичаена шема е да се пристапи до тајните во иницијалниот контејнер, кој ги обезбедува овие ингеренции до главниот модул, што спречува неовластен пристап до тајните од самиот главен модул на апликацијата.

Како и обично, цитат од документацијата: init контејнерите безбедно извршуваат кориснички код или услужни програми кои инаку би ја загрозиле безбедноста на сликата на контејнерот на апликацијата. Со чувањето на непотребните алатки одвоени, ја ограничувате површината на нападот на сликата на контејнерот на апликацијата.

Чекор пет: Конфигурација на кернелот

Конечно, ајде да зборуваме за понапредна техника.

Kubernetes е исклучително флексибилна платформа која ви овозможува да извршувате оптоварувања како што ви одговара. Имаме голем број високоефикасни апликации кои се исклучително интензивни за ресурси. Откако направивме опширно тестирање за оптоварување, откривме дека на една од апликациите и е тешко да се одржи во чекор со очекуваното оптоварување на сообраќајот кога важеа стандардните поставки на Kubernetes.

Сепак, Kubernetes ви дозволува да стартувате привилегиран контејнер што ги менува само параметрите на јадрото за одреден подлога. Еве што користевме за да го промениме максималниот број на отворени врски:

initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]

Ова е понапредна техника која често не е потребна. Но, ако вашата апликација се бори да се справи со тежок товар, можете да се обидете да измените некои од овие поставки. Повеќе информации за овој процес и поставување различни вредности - како и секогаш во официјалната документација.

Во заклучок

Иако Kubernetes може да изгледа како решение надвор од кутијата, постојат неколку клучни чекори што мора да се преземат за да се одржува непречено функционирање на апликациите.

За време на миграцијата во Кубернетес, важно е да се следи „циклусот за тестирање на оптоварување“: стартувајте ја апликацијата, тестирајте ја под оптоварување, набљудувајте ги метриките и однесувањето на скалирање, приспособете ја конфигурацијата врз основа на овие податоци, а потоа повторете го овој циклус повторно.

Бидете реални за очекуваниот сообраќај и обидете се да го надминете за да видите кои компоненти први се расипуваат. Со овој итеративен пристап, само неколку од наведените препораки може да бидат доволни за да се постигне успех. Или може да бара подлабоко прилагодување.

Секогаш поставувајте си ги овие прашања:

  1. Колку ресурси трошат апликациите и како ќе се промени оваа сума?
  2. Кои се вистинските барања за скалирање? Колку сообраќај во просек ќе се справи апликацијата? Што е со врвниот сообраќај?
  3. Колку често услугата ќе треба да се намалува? Колку брзо треба да се подигнат и работат новите подлоги за да се добие сообраќај?
  4. Колку грациозно се исклучуваат мешунките? Дали е тоа воопшто потребно? Дали е можно да се постигне распоредување без прекини?
  5. Како да се минимизираат безбедносните ризици и да се ограничи штетата од какви било компромитирани мешунки? Дали некои услуги имаат дозволи или пристапи што не им се потребни?

Kubernetes обезбедува неверојатна платформа која ви овозможува да ги користите најдобрите практики за да распоредите илјадници услуги во кластер. Сепак, сите апликации се различни. Понекогаш имплементацијата бара малку повеќе работа.

За среќа, Kubernetes ги обезбедува потребните поставки за постигнување на сите технички цели. Со користење на комбинација од барања и ограничувања за ресурси, сонди за Liveness и Readiness, иницирачки контејнери, мрежни политики и прилагодено подесување на кернелот, може да постигнете високи перформанси заедно со толеранција на грешки и брза приспособливост.

Што друго да прочитате:

  1. Најдобри практики и најдобри практики за водење контејнери и кубернети во производни средини.
  2. 90+ корисни алатки за Kubernetes: распоредување, управување, мониторинг, безбедност и повеќе.
  3. Нашиот канал околу Кубернетес во Телеграма.

Извор: www.habr.com

Додадете коментар