10 pogostih napak pri uporabi Kubernetesa

Opomba. prevod: Avtorji tega članka so inženirji iz majhnega češkega podjetja pipetail. Uspelo jim je sestaviti čudovit seznam [včasih banalnih, a vseeno] zelo perečih problemov in zmot, povezanih z delovanjem gruč Kubernetes.

10 pogostih napak pri uporabi Kubernetesa

V letih uporabe Kubernetesa smo delali z velikim številom gruč (tako upravljanih kot neupravljanih – na GCP, AWS in Azure). Sčasoma smo začeli opažati, da se nekatere napake nenehno ponavljajo. Vendar v tem ni sramota: večino smo jih naredili sami!

Članek vsebuje najpogostejše napake in omenja, kako jih odpraviti.

1. Viri: zahteve in omejitve

Ta artikel si vsekakor zasluži največjo pozornost in prvo mesto na seznamu.

CPE zahteva običajno bodisi sploh ni določeno bodisi ima zelo nizko vrednost (na vsako vozlišče postavite čim več podov). Tako postanejo vozlišča preobremenjena. V času velike obremenitve je procesorska moč vozlišča v celoti izkoriščena in določena delovna obremenitev prejme samo tisto, kar je "zahtevala". Dušenje procesorja. To povzroči povečano zakasnitev aplikacije, časovne omejitve in druge neprijetne posledice. (Več o tem preberite v našem drugem nedavnem prevodu: "Omejitve procesorja in agresivno dušenje v Kubernetesu« – pribl. prev.)

BestEffort (izjemno ne priporočljivo):

resources: {}

Izjemno nizka zahteva CPE (izjemno ne priporočljivo):

   resources:
      Requests:
        cpu: "1m"

Po drugi strani pa lahko prisotnost omejitve procesorja povzroči nerazumno preskakovanje urnih ciklov podov, tudi če procesor vozlišča ni popolnoma obremenjen. To lahko spet povzroči povečane zamude. Polemika se nadaljuje okoli parametra Kvota CPE CFS v jedru Linuxa in dušenje procesorja glede na nastavljene omejitve, kot tudi onemogočanje kvote CFS ... Žal, omejitve procesorja lahko povzročijo več težav, kot jih lahko rešijo. Več informacij o tem najdete na spodnji povezavi.

Pretirana izbira (pretiravanje) težave s spominom lahko povzročijo večje težave. Če dosežete omejitev procesorja, preskočite taktne cikle, medtem ko dosežete omejitev pomnilnika, uničite enoto. Ali ste kdaj opazili OOMkill? Da, točno o tem govorimo.

Ali želite čim bolj zmanjšati verjetnost, da se to zgodi? Ne dodeljujte preveč pomnilnika in uporabite Guaranteed QoS (Quality of Service), tako da nastavite zahtevo za pomnilnik na omejitev (kot v spodnjem primeru). Več o tem preberite v Predstavitve Henninga Jacobsa (vodilni inženir pri Zalandu).

Razpočen (večja možnost, da bo OOM ubit):

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

Zajamčena:

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

Kaj bi lahko pomagalo pri nastavljanju virov?

Z metrični strežnik lahko vidite trenutno porabo virov procesorja in porabo pomnilnika po sklopih (in vsebnikih v njih). Najverjetneje ga že uporabljate. Samo zaženite naslednje ukaze:

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

Vendar prikazujejo samo trenutno uporabo. Lahko vam da grobo predstavo o velikosti, a na koncu boste potrebovali zgodovino sprememb meritev skozi čas (če želite odgovoriti na vprašanja, kot so: "Kolikšna je bila največja obremenitev procesorja?", "Kakšna je bila obremenitev včeraj zjutraj?" itd.). Za to lahko uporabite Prometej, DataDog in druga orodja. Preprosto pridobijo metrike iz metričnega strežnika in jih shranijo, uporabnik pa jih lahko poizveduje in jih ustrezno nariše.

VerticalPodAutoscaler omogoča avtomatizirati ta proces. Sledi zgodovini uporabe procesorja in pomnilnika ter na podlagi teh informacij nastavi nove zahteve in omejitve.

Učinkovita uporaba računalniške moči ni lahka naloga. Kot da bi ves čas igrali Tetris. Če plačujete preveč za računalniško moč z nizko povprečno porabo (recimo ~10 %), priporočamo, da si ogledate izdelke, ki temeljijo na AWS Fargate ali Virtual Kubelet. Zgrajeni so na modelu zaračunavanja brez strežnika/plačilo po uporabi, ki se lahko v takih razmerah izkaže za cenejšega.

2. Sondi živahnosti in pripravljenosti

Privzeto preverjanja živahnosti in pripravljenosti v Kubernetesu niso omogočena. In včasih jih pozabijo prižgati...

Toda kako drugače lahko sprožite ponovni zagon storitve v primeru usodne napake? In kako izenačevalnik obremenitve ve, da je enota pripravljena sprejeti promet? Ali da zmore več prometa?

Ti testi se med seboj pogosto zamenjujejo:

  • Življenje — preverjanje „preživetja“, ki znova zažene enoto, če ne uspe;
  • Pripravljenost — preverjanje pripravljenosti, če ne uspe, prekine povezavo poda s storitvijo Kubernetes (to lahko preverite z kubectl get endpoints) in promet do njega ne pride, dokler ni uspešno opravljeno naslednje preverjanje.

Oba preverjanja IZVAJA V CELOTNEM ŽIVLJENJSKEM CIKLU POD. Je zelo pomembno.

Pogosta napačna predstava je, da se sonde pripravljenosti zaženejo samo ob zagonu, tako da lahko izravnalnik ve, da je pod pripravljen (Ready) in lahko začne obdelovati promet. Vendar je to le ena od možnosti njihove uporabe.

Druga je možnost, da ugotovimo, da je promet na pod čezmeren in ga preobremeni (ali pod izvaja izračune, ki zahtevajo veliko virov). V tem primeru pomaga preverjanje pripravljenosti zmanjšajte obremenitev stroka in ga »ohladite«.. Uspešen zaključek preverjanja pripravljenosti v prihodnosti omogoča ponovno povečajte obremenitev stroka. V tem primeru (če je test pripravljenosti neuspešen), bi bil neuspeh testa vzdržljivosti zelo kontraproduktiven. Zakaj znova zagnati enoto, ki je zdrava in trdo dela?

Zato je v nekaterih primerih bolje, da sploh ne preverjate, kot da jih omogočite z nepravilno konfiguriranimi parametri. Kot je navedeno zgoraj, če preverjanje pripravljenosti kopij, potem ste v velikih težavah. Možna možnost je konfiguracija samo test pripravljenostiIn nevarna živahnost pustite ob strani.

Obe vrsti preverjanj ne smeta spodleteti, ko ne uspejo običajne odvisnosti, sicer bo to pripeljalo do kaskadne (lavinske) okvare vseh sklopov. Z drugimi besedami, ne poškoduj se.

3. LoadBalancer za vsako storitev HTTP

Najverjetneje imate v gruči storitve HTTP, ki bi jih radi posredovali v zunanji svet.

Če storitev odprete kot type: LoadBalancer, bo njegov krmilnik (odvisno od ponudnika storitev) zagotovil in se dogovoril za zunanji LoadBalancer (ki ne deluje nujno na L7, temveč celo na L4), kar lahko vpliva na stroške (zunanji statični naslov IPv4, računalniška moč, zaračunavanje na sekundo ) zaradi potrebe po ustvarjanju velikega števila takih virov.

V tem primeru je veliko bolj logično uporabiti en zunanji izravnalnik obremenitve, odpiranje storitev kot type: NodePort. Ali še bolje, razširite nekaj podobnega nginx-ingress-controller (Ali traefik), ki bo edini Node Port končna točka, povezana z zunanjim izravnalnikom obremenitve, in bo usmerjala promet v gruči z uporabo vdor- Viri Kubernetes.

Druge (mikro)storitve znotraj gruče, ki med seboj komunicirajo, lahko »komunicirajo« z uporabo storitev, kot je GrozdIP in vgrajen mehanizem za odkrivanje storitev prek DNS. Samo ne uporabljajte njihovega javnega DNS/IP, saj lahko to vpliva na zakasnitev in poveča stroške storitev v oblaku.

4. Samodejno skaliranje gruče brez upoštevanja njenih značilnosti

Ko dodajate vozlišča v gručo in jih iz nje odstranjujete, se ne smete zanašati na nekatere osnovne meritve, kot je poraba procesorja na teh vozliščih. Načrtovanje pod mora upoštevati številne omejitve, kot so afiniteta pod/vozlišče, napake in toleracije, zahteve za vire, QoS itd. Uporaba zunanjega samodejnega skalirnika, ki teh odtenkov ne upošteva, lahko povzroči težave.

Predstavljajte si, da je treba načrtovati določeno enoto, vendar je zahtevana/razstavljena vsa razpoložljiva moč procesorja in enota se zatakne v stanju Pending. Zunanji samodejni skalirnik vidi povprečno trenutno obremenitev procesorja (ne zahtevane) in ne sproži razširitve (razširjeno) - ne doda drugega vozlišča. Posledično ta sklop ne bo načrtovan.

V tem primeru obratno skaliranje (približno) — odstranitev vozlišča iz gruče je vedno težje izvesti. Predstavljajte si, da imate pod s stanjem (s povezanim trajnim pomnilnikom). Trajne količine običajno pripadajo specifično območje razpoložljivosti in se ne posnemajo v regiji. Če torej zunanji samodejni skalirnik izbriše vozlišče s tem sklopom, razporejevalnik ne bo mogel načrtovati tega sklopa na drugem vozlišču, saj je to mogoče storiti le v območju razpoložljivosti, kjer se nahaja trajni pomnilnik. Pod bo obstal v stanju Pending.

Zelo priljubljen v skupnosti Kubernetes cluster-autoscaler. Deluje v gruči, podpira API-je večjih ponudnikov oblakov, upošteva vse omejitve in se lahko spreminja v zgornjih primerih. Prav tako se lahko poveča, medtem ko ohranja vse nastavljene omejitve, s čimer prihrani denar (ki bi ga sicer porabili za neizkoriščeno zmogljivost).

5. Zanemarjanje zmogljivosti IAM/RBAC

Pazite se uporabe uporabnikov IAM s trajnimi skrivnostmi za stroji in aplikacije. Organizirajte začasni dostop z uporabo vlog in storitvenih računov (storitveni računi).

Pogosto se srečamo z dejstvom, da so dostopni ključi (in skrivnosti) trdo kodirani v konfiguraciji aplikacije, pa tudi zanemarjanje rotacije skrivnosti kljub dostopu do Cloud IAM. Uporabite vloge IAM in storitvene račune namesto uporabnikov, kjer je primerno.

10 pogostih napak pri uporabi Kubernetesa

Pozabite na kube2iam in pojdite naravnost na vloge IAM za storitvene račune (kot je opisano v zapis z istim imenom Štěpán Vraný):

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

Ena opomba. Ni tako težko, kajne?

Prav tako ne podeljujte privilegijev za storitvene račune in profile primerkov admin и cluster-adminče ga ne potrebujejo. To je nekoliko težje izvesti, zlasti v RBAC K8, vendar je vsekakor vredno truda.

6. Ne zanašajte se na samodejno preprečevanje afinitete za stroke

Predstavljajte si, da imate tri replike neke razmestitve na vozlišču. Vozlišče pade in z njim vse replike. Neprijetna situacija, kajne? Toda zakaj so bile vse replike na istem vozlišču? Ali naj Kubernetes ne bi zagotavljal visoke razpoložljivosti (HA)?!

Na žalost razporejevalnik Kubernetes na lastno pobudo ne upošteva pravil ločenega obstoja (proti afiniteti) za stroke. Izrecno morajo biti navedeni:

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

To je vse. Zdaj bodo podi načrtovani na različnih vozliščih (ta pogoj je preverjen le med razporejanjem, ne pa tudi med njihovim delovanjem – torej requiredDuringSchedulingIgnoredDuringExecution).

Tukaj govorimo o podAntiAffinity na različnih vozliščih: topologyKey: "kubernetes.io/hostname", - in ne o različnih območjih razpoložljivosti. Če želite implementirati popolno HA, se boste morali poglobiti v to temo.

7. Ignoriranje PodDisruptionBudgets

Predstavljajte si, da imate produkcijsko obremenitev gruče Kubernetes. Občasno je treba vozlišča in samo gručo posodobiti (ali razgraditi). PodDisruptionBudget (PDB) je nekaj podobnega pogodbi o garanciji storitev med skrbniki gruče in uporabniki.

PDB vam omogoča, da se izognete prekinitvam storitev zaradi pomanjkanja vozlišč:

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

V tem primeru vi, kot uporabnik gruče, izjavite skrbnikom: "Hej, imam storitev zookeeper in ne glede na to, kaj počnete, bi rad imel vedno na voljo vsaj 2 repliki te storitve."

Več o tem si lahko preberete tukaj.

8. Več uporabnikov ali okolij v skupni gruči

Imenski prostori Kubernetes (imenski prostori) ne zagotavljajo močne izolacije.

Pogosta napačna predstava je, da če uvedete neproizvodno nalaganje v en imenski prostor in proizvodno nalaganje v drugega, ne bosta na noben način vplivala drug na drugega... Vendar pa je določeno raven izolacije mogoče doseči z uporabo zahtev/omejitev virov, nastavitvijo kvot in nastavitvijo priorityClasses. Nekaj ​​»fizične« izolacije v podatkovni ravni zagotavljajo afinitete, tolerance, madeži (ali izbirniki vozlišč), vendar je taka ločitev precej težko izvajati.

Tisti, ki morajo združiti obe vrsti delovnih obremenitev v istem grozdu, se bodo morali soočiti s kompleksnostjo. Če te potrebe ni in si jo lahko privoščite še en grozd (recimo v javnem oblaku), potem je bolje, da to storite. S tem boste dosegli veliko višjo stopnjo izolacije.

9. externalTrafficPolicy: Cluster

Zelo pogosto opazimo, da ves promet znotraj gruče poteka prek storitve, kot je NodePort, za katero je nastavljen privzeti pravilnik externalTrafficPolicy: Cluster... To pomeni, da Node Port je odprt na vsakem vozlišču v gruči in katerega koli od njih lahko uporabite za interakcijo z želeno storitvijo (nabor podov).

10 pogostih napak pri uporabi Kubernetesa

Hkrati so pravi podi, povezani z zgoraj omenjeno storitvijo NodePort, običajno na voljo le na določeni podmnožica teh vozlišč. Z drugimi besedami, če se povežem z vozliščem, ki nima zahtevanega modula, bo posredovalo promet drugemu vozlišču, dodajanje hmelja in povečanje zakasnitve (če so vozlišča v različnih območjih razpoložljivosti/podatkovnih centrih, je lahko zakasnitev precej visoka; poleg tega se bodo povečali stroški izhodnega prometa).

Po drugi strani pa, če ima določena storitev Kubernetes nastavljen pravilnik externalTrafficPolicy: Local, potem se NodePort odpre samo na tistih vozliščih, kjer se zahtevani pods dejansko izvajajo. Pri uporabi zunanjega izravnalnika obremenitve, ki preverja stanje (zdravstveni pregled) končne točke (kako deluje AWS ELB), On bo pošiljal promet samo do potrebnih vozlišč, kar bo blagodejno vplivalo na zamude, računalniške potrebe, izhodne račune (in zdrav razum narekuje isto).

Obstaja velika verjetnost, da že uporabljate kaj podobnega traefik ali nginx-ingress-controller kot končna točka NodePort (ali LoadBalancer, ki prav tako uporablja NodePort) za usmerjanje vhodnega prometa HTTP, nastavitev te možnosti pa lahko znatno zmanjša zakasnitev za takšne zahteve.

В ta publikacija Izvedete lahko več o externalTrafficPolicy, njegovih prednostih in slabostih.

10. Ne vežite se na grozde in ne zlorabljajte nadzorne ravnine

Prej je bilo običajno klicati strežnike s pravimi imeni: Anton, HAL9000 in Colossus ... Danes so jih nadomestili naključno generirani identifikatorji. Vendar je navada ostala in zdaj gredo lastna imena v grozde.

Tipična zgodba (temelji na resničnih dogodkih): vse se je začelo z dokazom koncepta, zato je imel grozd ponosno ime Testiranje… Minila so leta in se ŠE VEDNO uporablja v proizvodnji in vsi se ga bojijo dotakniti.

Nič zabavnega ni v tem, da se grozdi spremenijo v hišne ljubljenčke, zato priporočamo, da jih med vadbo občasno odstranite obnovitev po nesreči (to bo pomagalo inženirstvo kaosa — pribl. prev.). Poleg tega ne bi škodilo delati na kontrolni plasti (kontrolna ravnina). To, da se ga je strah dotakniti, ni dober znak. itd mrtev? Fantje, res ste v težavah!

Po drugi strani pa se ne smete zanesti z manipulacijo. S časom nadzorna plast lahko postane počasna. Najverjetneje je to posledica velikega števila predmetov, ustvarjenih brez vrtenja (običajna situacija pri uporabi Helma s privzetimi nastavitvami, zaradi česar se njegovo stanje v konfiguracijskih zemljevidih/skrivnostih ne posodablja - posledično se na tisoče objektov nabere v nadzorni sloj) ali s stalnim urejanjem predmetov kube-api (za samodejno skaliranje, za CI/CD, za spremljanje, dnevnike dogodkov, krmilnike itd.).

Poleg tega priporočamo, da preverite pogodbe SLA/SLO z upravljanim ponudnikom Kubernetes in ste pozorni na garancije. Prodajalec lahko jamči razpoložljivost nadzornega sloja (ali njegove podkomponente), ne pa tudi zakasnitve p99 zahtev, ki mu jih pošljete. Z drugimi besedami, lahko vstopite kubectl get nodes, in prejmete odgovor šele po 10 minutah in to ne bo kršitev pogojev pogodbe o storitvi.

11. Bonus: uporaba najnovejše oznake

Ampak to je že klasika. V zadnjem času se s to tehniko srečujemo manj pogosto, saj so mnogi, poučeni iz grenkih izkušenj, prenehali uporabljati oznako :latest in začel pripenjati različice. Hura!

ECR ohranja nespremenljivost slikovnih oznak; Priporočamo, da se seznanite s to izjemno funkcijo.

Povzetek

Ne pričakujte, da bo vse delovalo čez noč: Kubernetes ni rešitev. Slaba aplikacija tako bo ostalo tudi v Kubernetesu (in verjetno bo še slabše). Nepazljivost bo povzročila pretirano kompleksnost, počasno in stresno delo nadzorne plasti. Poleg tega tvegate, da boste ostali brez strategije za obnovitev po katastrofi. Ne pričakujte, da bo Kubernetes takoj po namestitvi zagotovil izolacijo in visoko razpoložljivost. Porabite nekaj časa, da bo vaša aplikacija resnično izvorna v oblaku.

Z neuspešnimi izkušnjami različnih ekip se lahko seznanite v to zbirko zgodb avtorja Henning Jacobs.

Tisti, ki se želijo dodati na seznam napak v tem članku, nas lahko kontaktirajo na Twitterju (@MarekBartik, @MstrsObserver).

PS od prevajalca

Preberite tudi na našem blogu:

Vir: www.habr.com

Dodaj komentar