Pet promašaja prilikom postavljanja prve aplikacije na Kubernetes

Pet promašaja prilikom postavljanja prve aplikacije na KubernetesFail od Arisa Dreamera

Mnogi ljudi misle da je dovoljno prebaciti aplikaciju u Kubernetes (bilo pomoću Helma ili ručno) - i bit će sreće. Ali nije sve tako jednostavno.

Momčad Mail.ru Cloud rješenja preveo članak DevOps inženjera Juliana Gindyja. Govori s kojim se zamkama njegova tvrtka susrela tijekom procesa migracije kako ne biste stali na iste grablje.

Prvi korak: Postavite zahtjeve i ograničenja za pod

Počnimo s postavljanjem čistog okoliša u kojem će naše mahune raditi. Kubernetes je izvrstan u raspoređivanju podova i prelasku. No pokazalo se da planer ponekad ne može postaviti pod ako je teško procijeniti koliko mu resursa treba za uspješan rad. Ovdje se pojavljuju zahtjevi za resursima i ograničenjima. Puno se raspravlja o najboljem pristupu postavljanju zahtjeva i ograničenja. Ponekad se čini da je ovo zapravo više umjetnost nego znanost. Evo našeg pristupa.

Pod zahtjevi je glavna vrijednost koju planer koristi za optimalno postavljanje modula.

Od Kubernetes dokumentacija: Korak filtra definira skup čvorova gdje se Pod može zakazati. Na primjer, filtar PodFitsResources provjerava ima li čvor dovoljno resursa da zadovolji specifične zahtjeve resursa iz modula.

Zahtjeve aplikacija koristimo na način da možemo procijeniti koliko resursa u stvari Aplikaciji je to potrebno za pravilan rad. Na taj način planer može realno postaviti čvorove. U početku smo željeli previše rasporediti zahtjeve kako bismo osigurali dovoljno resursa za svaki Pod, ali primijetili smo da se vrijeme zakazivanja značajno povećalo, a neki Podovi nisu bili u potpunosti raspoređeni, kao da za njih nema zahtjeva za resursima.

U ovom slučaju, planer bi često "iscijedio" mahune i ne bi ih mogao ponovno rasporediti jer kontrolna razina nije imala pojma koliko resursa treba aplikaciji, što je ključna komponenta algoritma za raspored.

Granice mahuna je jasnija granica za pod. Predstavlja maksimalnu količinu resursa koje će klaster dodijeliti spremniku.

Opet, iz službena dokumentacija: Ako spremnik ima ograničenje memorije od 4 GiB, tada će ga kubelet (i vrijeme izvođenja spremnika) nametnuti. Vrijeme izvođenja sprječava spremnik da koristi više od navedenog ograničenja resursa. Na primjer, kada proces u spremniku pokuša koristiti više od dopuštene količine memorije, jezgra sustava prekida proces s pogreškom "nema memorije" (OOM).

Spremnik uvijek može koristiti više resursa nego što je navedeno u zahtjevu za resurs, ali nikada ne može koristiti više od ograničenja. Ovu vrijednost je teško ispravno postaviti, ali je vrlo važna.

U idealnom slučaju, želimo da se zahtjevi za resursima modula mijenjaju tijekom životnog ciklusa procesa bez ometanja drugih procesa u sustavu - to je svrha postavljanja ograničenja.

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

  1. Pomoću alata za testiranje opterećenja simuliramo osnovnu razinu prometa i promatramo korištenje resursa pod (memorija i procesor).
  2. Postavite pod zahtjeve na proizvoljno nisku vrijednost (s ograničenjem resursa od oko 5 puta vrijednosti zahtjeva) i promatrajte. Kada su zahtjevi na preniskoj razini, proces se ne može pokrenuti, što često uzrokuje zagonetne pogreške Go runtimea.

Napominjem da viša ograničenja resursa otežavaju zakazivanje jer pod treba ciljni čvor s dovoljno dostupnih resursa.

Zamislite situaciju u kojoj imate lagani web poslužitelj s vrlo visokim ograničenjem resursa, poput 4 GB memorije. Ovaj će se proces vjerojatno morati horizontalno skalirati, a svaki novi pod će morati biti zakazan na čvoru s najmanje 4 GB dostupne memorije. Ako takav čvor ne postoji, klaster mora uvesti novi čvor za obradu ovog modula, što može potrajati neko vrijeme. Važno je postići minimalnu razliku između zahtjeva za resursima i ograničenja kako bi se osiguralo brzo i glatko skaliranje.

Drugi korak: Postavite testove živosti i spremnosti

Ovo je još jedna suptilna tema o kojoj se često raspravlja u Kubernetes zajednici. Važno je dobro razumjeti testove Liveness i Readiness jer oni pružaju mehanizam za stabilan rad softvera i minimiziraju vrijeme prekida rada. Međutim, oni mogu ozbiljno utjecati na performanse vaše aplikacije ako nisu ispravno konfigurirani. U nastavku je sažetak onoga što su oba uzorka.

Živost pokazuje radi li spremnik. Ako ne uspije, kubelet uništava spremnik i za njega je omogućeno pravilo ponovnog pokretanja. Ako spremnik nije opremljen Liveness Probeom, tada će zadano stanje biti uspješno - kao što je navedeno u Kubernetes dokumentacija.

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

Ako postavite opciju pokretanja svake sekunde, to će dodati 1 zahtjev po sekundi, stoga imajte na umu da će za obradu ovog prometa biti potrebni dodatni resursi.

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

Postavili smo krajnju točku "zdravlja" u aplikacijama koje jednostavno vraćaju kod odgovora 200. To je pokazatelj da je proces pokrenut i da može obraditi zahtjeve (ali još ne i promet).

test Spremnost pokazuje da li je spremnik spreman za posluživanje zahtjeva. Ako sonda spremnosti ne uspije, kontroler krajnje točke uklanja IP adresu modula s krajnjih točaka svih usluga koje odgovaraju modulu. To je također navedeno u Kubernetes dokumentaciji.

Probe spremnosti troše više resursa jer moraju doći do pozadine na takav način da pokažu da je aplikacija spremna prihvatiti zahtjeve.

U zajednici se puno raspravlja o tome treba li izravno pristupiti bazi podataka. S obzirom na troškove (provjere su česte, ali se mogu kontrolirati), odlučili smo da se za neke aplikacije spremnost za opsluživanje prometa broji tek nakon provjere jesu li zapisi vraćeni iz baze podataka. Dobro osmišljeni testovi spremnosti osigurali su više razine dostupnosti i eliminirali zastoje tijekom implementacije.

Ako odlučite postaviti upit bazi podataka kako biste testirali spremnost svoje aplikacije, pobrinite se da bude što jeftiniji. Uzmimo ovaj upit:

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 lansiranja sondi.
  • periodSeconds — interval čekanja između uzoraka.
  • timeoutSeconds — broj sekundi nakon kojih se kapsula smatra hitnom. Normalno vremensko ograničenje.
  • failureThreshold je broj neuspjelih testova prije nego što se signal ponovnog pokretanja pošalje modulu.
  • successThreshold je broj uspješnih pokušaja prije nego što modul prijeđe u stanje pripravnosti (nakon kvara kada se modul pokrene ili oporavi).

Treći korak: Postavljanje zadanih mrežnih pravila Poda

Kubernetes ima "ravnu" topografiju mreže, prema zadanim postavkama svi moduli komuniciraju izravno jedni s drugima. U nekim slučajevima to nije poželjno.

Potencijalni sigurnosni problem je da bi napadač mogao upotrijebiti jednu ranjivu aplikaciju za slanje prometa na sve module na mreži. Kao iu mnogim područjima sigurnosti, ovdje vrijedi načelo najmanje privilegije. U idealnom slučaju, mrežna pravila trebala bi izričito navesti koje su veze između modula dopuštene, a koje nisu.

Na primjer, sljedeće je jednostavno pravilo koje 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 pojedinosti здесь.

Četvrti korak: Prilagođeno ponašanje s kukicama i početnim spremnicima

Jedan od naših glavnih ciljeva bio je osigurati implementacije u Kubernetesu bez zastoja za programere. To je teško jer postoji mnogo opcija za gašenje aplikacija i oslobađanje njihovih iskorištenih resursa.

Osobite su se poteškoće pojavile s Nginx. Primijetili smo da su se aktivne veze prekidale prije uspješnog dovršetka pri postavljanju ovih jedinica u nizu.

Nakon opsežnog istraživanja na internetu, pokazalo se da Kubernetes ne čeka da se Nginx veze iscrpe prije nego što isključi pod. Uz pomoć pre-stop kuke implementirali smo sljedeće funkcionalnosti 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 korištenje init spremnika za upravljanje pokretanjem specifičnih aplikacija. Ovo je posebno korisno ako imate proces migracije baze podataka koji zahtijeva mnogo resursa i mora se pokrenuti prije pokretanja aplikacije. Također možete navesti veće ograničenje resursa za ovaj proces bez postavljanja takvog ograničenja za glavnu aplikaciju.

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

Kao i obično, citat iz dokumentacije: init spremnici sigurno pokreću prilagođeni kod ili pomoćne programe koji bi inače ugrozili sigurnost slike spremnika aplikacije. Odvojenim držanjem nepotrebnih alata ograničavate površinu napada slike spremnika aplikacije.

Peti korak: Konfiguracija kernela

Na kraju, razgovarajmo o naprednijoj tehnici.

Kubernetes je iznimno fleksibilna platforma koja vam omogućuje pokretanje radnih opterećenja kako god želite. Imamo brojne visoko učinkovite aplikacije koje zahtijevaju izuzetno mnogo resursa. Nakon opsežnog testiranja opterećenja, otkrili smo da je jedna od aplikacija teško pratila očekivano opterećenje prometa kada su zadane postavke Kubernetesa bile na snazi.

Međutim, Kubernetes vam omogućuje pokretanje privilegiranog spremnika koji mijenja samo parametre kernela za određeni pod. Evo što smo upotrijebili 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 bori s velikim opterećenjem, možete pokušati podesiti neke od ovih postavki. Više informacija 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 rješenje izvan okvira, postoji nekoliko ključnih koraka koje je potrebno poduzeti kako bi aplikacije radile glatko.

Tijekom migracije na Kubernetes važno je slijediti "ciklus testiranja opterećenja": pokrenite aplikaciju, testirajte je pod opterećenjem, promatrajte metriku i ponašanje skaliranja, prilagodite konfiguraciju na temelju ovih podataka, a zatim ponovno ponovite ovaj ciklus.

Budite realni u pogledu očekivanog prometa i pokušajte ga nadmašiti kako biste vidjeli koje se komponente prve pokvare. Uz ovaj iterativni pristup, samo nekoliko od navedenih preporuka može biti dovoljno za postizanje uspjeha. Ili će možda biti potrebna dublja prilagodba.

Uvijek si postavite ova pitanja:

  1. Koliko resursa troše aplikacije i kako će se taj iznos promijeniti?
  2. Koji su stvarni zahtjevi za skaliranje? Koliki će promet aplikacija u prosjeku podnijeti? Što je s vršnim prometom?
  3. Koliko često će se usluga morati proširiti? Koliko brzo novi blokovi moraju biti pokrenuti da prime promet?
  4. Koliko se graciozno zatvaraju kapsule? Je li to uopće potrebno? Je li moguće postići implementaciju bez zastoja?
  5. Kako minimizirati sigurnosne rizike i ograničiti štetu od bilo koje kompromitirane jedinice? Imaju li neke usluge dopuštenja ili pristupe koji im nisu potrebni?

Kubernetes pruža nevjerojatnu platformu koja vam omogućuje korištenje najboljih praksi za implementaciju tisuća usluga u klasteru. Međutim, sve su aplikacije različite. Ponekad implementacija zahtijeva malo više posla.

Srećom, Kubernetes pruža potrebne postavke za postizanje svih tehničkih ciljeva. Korištenjem kombinacije zahtjeva za resursima i ograničenja, sondi Liveness i Readiness, init spremnika, mrežnih pravila i prilagođenog podešavanja jezgre, možete postići visoku izvedbu zajedno s tolerancijom grešaka i brzom skalabilnošću.

Što još pročitati:

  1. Najbolji primjeri iz prakse i najbolji primjeri iz prakse za pokretanje spremnika i Kubernetesa u produkcijskim okruženjima.
  2. 90+ korisnih alata za Kubernetes: implementacija, upravljanje, nadzor, sigurnost i više.
  3. Naš kanal Oko Kubernetesa u Telegramu.

Izvor: www.habr.com

Dodajte komentar