Pet promašaja prilikom postavljanja prve aplikacije na Kubernetes

Pet promašaja prilikom postavljanja prve aplikacije na KubernetesFail by Aris-Dreamer

Mnogi ljudi vjeruju da je dovoljno da migriraju aplikaciju na Kubernetes (bilo koristeći Helm ili ručno) i bit će sretni. Ali to nije tako jednostavno.

tim Mail.ru Cloud rješenja preveo je članak DevOps inženjera Juliana Gindija. On dijeli na koje zamke je njegova kompanija naišla tokom procesa migracije kako ne biste nagazili na iste grablje.

Prvi korak: Postavljanje Pod zahtjeva i ograničenja

Počnimo sa postavljanjem čistog okruženja u kojem će naši podovi raditi. Kubernetes radi odličan posao planiranja podova i rukovanja uslovima kvara. Ali pokazalo se da planer ponekad ne može postaviti pod ako je teško procijeniti koliko resursa mu je potrebno za uspješan rad. Ovdje se pojavljuju zahtjevi za resursima i ograničenjima. Mnogo je debata o najboljem pristupu postavljanju zahtjeva i ograničenja. Ponekad se zaista čini da je to više umjetnost nego nauka. Evo našeg pristupa.

Pod zahtjevi - Ovo je glavna vrijednost koju koristi planer za optimalno postavljanje kapsule.

Od Kubernetes dokumentacija: Korak filtriranja određuje skup čvorova na kojima se pod može rasporediti. Na primjer, filter PodFitsResources provjerava da li čvor ima dovoljno resursa da zadovolji specifične zahtjeve za resurse modula.

Koristimo zahtjeve aplikacije kako bi se mogli koristiti za procjenu koliko resursa zapravo Aplikacija treba da radi ispravno. Na ovaj način planer može realno postaviti čvorove. Prvobitno smo željeli postaviti zahtjeve s marginom kako bismo osigurali da svaki pod ima dovoljno veliki broj resursa, ali smo primijetili da se vrijeme zakazivanja značajno povećalo i da neki podovi nikada nisu bili u potpunosti zakazani, kao da za njih nisu primljeni zahtjevi za resursima.

U ovom slučaju, planer bi često izbacio podove i ne bi mogao da ih reprogramira jer kontrolna ravan nije imala pojma koliko resursa treba aplikaciji, što je ključna komponenta algoritma za planiranje.

Pod limiti - ovo je jasnija granica za mahunu. Predstavlja maksimalnu količinu resursa koju će klaster dodijeliti kontejneru.

Opet, od službena dokumentacija: Ako kontejner ima postavljeno ograničenje memorije od 4 GiB, tada će ga kubelet (i vrijeme izvođenja spremnika) primijeniti. Vrijeme izvođenja ne dopušta kontejneru da koristi više od navedenog ograničenja resursa. Na primjer, kada proces u kontejneru pokuša koristiti više od dozvoljene količine memorije, sistemsko jezgro završava proces greškom "nedostaje memorije" (OOM).

Kontejner uvijek može koristiti više resursa nego što je navedeno u zahtjevu za resurse, ali nikada ne može koristiti više od navedenog u ograničenju. Ovu vrijednost je teško ispravno postaviti, ali je veoma važna.

U idealnom slučaju, želimo da se zahtjevi za resursima modula mijenjaju tokom životnog ciklusa procesa bez ometanja drugih procesa u sistemu – to je cilj postavljanja ograničenja.

Nažalost, ne mogu dati konkretne upute koje vrijednosti postaviti, ali se i sami pridržavamo sljedećih pravila:

  1. Koristeći alat za testiranje opterećenja, simuliramo osnovni nivo prometa i pratimo korištenje pod resursa (memorije i procesora).
  2. Postavljamo pod zahtjeve na proizvoljno nisku vrijednost (sa ograničenjem resursa od oko 5 puta većom od vrijednosti zahtjeva) i promatramo. Kada su zahtjevi preniski, proces ne može započeti, što često uzrokuje misteriozne greške Go runtime-a.

Imajte na umu da veća ograničenja resursa otežavaju zakazivanje jer pod treba ciljni čvor s dovoljno dostupnih resursa.

Zamislite situaciju u kojoj imate lagani web server sa vrlo visokim ograničenjem resursa, recimo 4 GB memorije. Ovaj proces će vjerovatno morati horizontalno skalirati, a svaki novi modul će morati biti zakazan na čvoru s najmanje 4 GB dostupne memorije. Ako takav čvor ne postoji, klaster mora uvesti novi čvor za obradu tog modula, što može potrajati. Važno je svesti razliku između zahtjeva za resursima i ograničenja na minimum kako bi se osiguralo brzo i glatko skaliranje.

Drugi korak: postavljanje testova živosti i spremnosti

Ovo je još jedna suptilna tema o kojoj se često raspravlja u Kubernetes zajednici. Važno je dobro razumjeti testove živosti i spremnosti jer oni pružaju mehanizam za neometano funkcioniranje softvera i minimiziranje zastoja. Međutim, oni mogu uzrokovati ozbiljan pad performansi vašoj aplikaciji ako nisu ispravno konfigurirani. Ispod je sažetak kako izgledaju oba uzorka.

Život pokazuje da li je kontejner pokrenut. Ako ne uspije, kubelet ubija kontejner i za njega je omogućena politika ponovnog pokretanja. Ako kontejner nije opremljen Liveness sondom, tada će zadano stanje biti uspješno - ovako piše u Kubernetes dokumentacija.

Liveness sonde bi trebale biti jeftine, što znači da ne bi trebale trošiti puno resursa, jer se često pokreću i trebaju obavijestiti Kubernetes da je aplikacija pokrenuta.

Ako postavite opciju da se pokreće svake sekunde, to će dodati 1 zahtjev u sekundi, stoga imajte na umu da će biti potrebni dodatni resursi za rukovanje ovim prometom.

U našoj kompaniji Liveness testovi provjeravaju osnovne komponente aplikacije, čak i ako podaci (na primjer, iz udaljene baze podataka ili keša) nisu u potpunosti dostupni.

Konfigurisali smo aplikacije sa "zdravstvenom" krajnjom tačkom koja jednostavno vraća kod odgovora 200. Ovo je indikacija da je proces pokrenut i da je sposoban za obradu zahtjeva (ali još ne i promet).

Primer Spremnost označava da li je kontejner spreman za posluživanje zahtjeva. Ako sonda spremnosti ne uspije, kontroler krajnje točke uklanja IP adresu modula sa krajnjih tačaka svih usluga koje odgovaraju modulu. Ovo je takođe navedeno u Kubernetes dokumentaciji.

Probe spremnosti troše više resursa jer se moraju poslati na pozadinu na način koji pokazuje da je aplikacija spremna da prihvati zahtjeve.

U zajednici se vodi mnogo debata o tome da li pristupiti bazi podataka direktno. S obzirom na opterećenje (provjere se obavljaju često, ali se mogu prilagoditi), odlučili smo da se za neke aplikacije spremnost za opsluživanje saobraćaja računa tek nakon provjere da se zapisi vraćaju iz baze podataka. Dobro osmišljena ispitivanja spremnosti osigurala su viši nivo dostupnosti i eliminisala zastoje tokom implementacije.

Ako odlučite da postavite upit bazi podataka kako biste testirali spremnost vaše aplikacije, pobrinite se da bude što jeftinija. Prihvatimo ovaj zahtjev:

SELECT small_item FROM table LIMIT 1

Evo primjera kako konfiguriramo ove dvije vrijednosti u Kubernetesu:

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

Možete dodati neke dodatne opcije konfiguracije:

  • initialDelaySeconds — koliko će sekundi proći između lansiranja kontejnera i početka uzoraka.
  • periodSeconds — interval čekanja između pokretanja uzorka.
  • timeoutSeconds — broj sekundi nakon kojih se jedinica smatra hitnom. Regular timeout.
  • failureThreshold — broj neuspjeha testa prije nego što se signal ponovnog pokretanja pošalje u pod.
  • successThreshold — broj uspješnih sondi prije nego što modul prijeđe u stanje spremnosti (nakon kvara, kada se modul pokrene ili oporavi).

Treći korak: postavljanje zadanih mrežnih politika za pod

Kubernetes ima „ravnu“ topografiju mreže; po defaultu, svi podovi međusobno komuniciraju direktno. U nekim slučajevima to nije poželjno.

Potencijalni sigurnosni problem je da bi napadač mogao koristiti jednu ranjivu aplikaciju za slanje prometa svim podovima na mreži. Kao iu mnogim oblastima sigurnosti, i ovdje se primjenjuje princip najmanje privilegija. U idealnom slučaju, mrežne politike bi trebale eksplicitno specificirati koje su veze između podova dozvoljene, a koje ne.

Na primjer, ispod je jednostavna politika koja odbija sav dolazni promet za određeni prostor imena:

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

Vizualizacija ove konfiguracije:

Pet promašaja prilikom postavljanja prve aplikacije na Kubernetes
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Više detalja ovdje.

Četvrti korak: prilagođeno ponašanje pomoću kukica i init kontejnera

Jedan od naših glavnih ciljeva bio je da omogućimo implementaciju Kubernetesa bez prekida za programere. To je teško jer postoji mnogo opcija za gašenje aplikacija i oslobađanje resursa koje su koristili.

Posebne poteškoće su nastale sa Nginx. Primijetili smo da kada su ovi podovi raspoređeni uzastopno, aktivne veze su prekinute prije uspješnog završetka.

Nakon opsežnog istraživanja na mreži, pokazalo se da Kubernetes ne čeka da se Nginx konekcije iscrpe prije nego što prekine pod. Koristeći pre-stop kuku, implementirali smo sljedeću funkcionalnost i potpuno se riješili zastoja:

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

Ali 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

Još jedna izuzetno korisna paradigma je upotreba init kontejnera za rukovanje pokretanjem određenih aplikacija. Ovo je posebno korisno ako imate proces migracije baze podataka koji zahtijeva puno resursa i koji se mora pokrenuti prije pokretanja aplikacije. Također možete odrediti veće ograničenje resursa za ovaj proces bez postavljanja takvog ograničenja za glavnu aplikaciju.

Druga uobičajena šema je pristup tajnama u init kontejneru koji daje te vjerodajnice glavnom modulu, što sprječava neovlašteni pristup tajnama iz samog modula glavne aplikacije.

Kao i obično, citirajte iz dokumentacije: Init kontejneri sigurno pokreću prilagođeni kod ili uslužne programe koji bi inače smanjili sigurnost slike kontejnera aplikacije. Držanjem nepotrebnih alata odvojenim, ograničavate površinu napada slike kontejnera aplikacije.

Peti korak: Konfiguracija kernela

Na kraju, hajde da pričamo o naprednijoj tehnici.

Kubernetes je izuzetno fleksibilna platforma koja vam omogućava da izvršavate radna opterećenja onako kako vam odgovara. Imamo veliki broj aplikacija visokih performansi koje su izuzetno intenzivni. Nakon sprovođenja opsežnog testiranja opterećenja, otkrili smo da se jedna aplikacija bori sa očekivanim opterećenjem saobraćaja kada su Kubernetes-ove zadane postavke bile na snazi.

Međutim, Kubernetes vam omogućava da pokrenete privilegirani kontejner koji mijenja parametre kernela samo za određeni pod. Evo šta smo koristili za promjenu maksimalnog broja otvorenih veza:

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

Ovo je naprednija tehnika koja često nije potrebna. Ali ako se vaša aplikacija teško nosi s velikim opterećenjem, možete pokušati podesiti neke od ovih postavki. Više detalja o ovom procesu i postavljanju različitih vrijednosti - kao i uvijek u službenoj dokumentaciji.

U zaključku

Iako se Kubernetes može činiti kao gotovo rješenje iz kutije, postoji nekoliko ključnih koraka koje morate poduzeti da bi vaše aplikacije radile nesmetano.

Tokom vaše Kubernetes migracije, važno je pratiti "ciklus testiranja opterećenja": pokrenite aplikaciju, testirajte je učitavanjem, promatrajte metriku i ponašanje skaliranja, prilagodite konfiguraciju na osnovu tih podataka, a zatim ponovite ciklus ponovo.

Budite realni u pogledu očekivanog saobraćaja i pokušajte da ga prevaziđete da vidite koje komponente se prve pokvare. Uz ovaj iterativni pristup, samo nekoliko od navedenih preporuka može biti dovoljno za postizanje uspjeha. Ili može zahtijevati dublje prilagođavanje.

Uvijek si postavljajte ova pitanja:

  1. Koliko resursa troše aplikacije i kako će se taj volumen promijeniti?
  2. Koji su stvarni zahtjevi za skaliranje? Koliko prometa će aplikacija u prosjeku podnijeti? Šta je sa vršnim prometom?
  3. Koliko često će se usluga morati horizontalno skalirati? Koliko brzo nove podove treba dovesti na mrežu da bi primili promet?
  4. Koliko se pravilno gase mahune? Da li je ovo uopšte potrebno? Da li je moguće postići implementaciju bez zastoja?
  5. Kako možete minimizirati sigurnosne rizike i ograničiti štetu od bilo kojeg kompromitovanog modula? Imaju li neki servisi dozvole ili pristup koji im nisu potrebni?

Kubernetes pruža nevjerovatnu platformu koja vam omogućava da iskoristite najbolje prakse za implementaciju hiljada usluga u klasteru. Međutim, svaka aplikacija je drugačija. Ponekad implementacija zahtijeva malo više rada.

Na sreću, Kubernetes pruža potrebnu konfiguraciju za postizanje svih tehničkih ciljeva. Koristeći kombinaciju zahtjeva za resurse i ograničenja, probe Liveness i Readiness, init kontejnera, mrežnih politika i prilagođenog podešavanja kernela, možete postići visoke performanse zajedno sa tolerancijom grešaka i brzom skalabilnosti.

Šta još pročitati:

  1. Najbolje prakse i najbolje prakse za pokretanje kontejnera i Kubernetesa u proizvodnim okruženjima.
  2. 90+ korisnih alata za Kubernetes: implementacija, upravljanje, nadzor, sigurnost i još mnogo toga.
  3. Naš kanal Oko Kubernetesa u Telegramu.

izvor: www.habr.com

Dodajte komentar