10 tüüpilist viga Kuberneteset kasutades

Märk. tõlge.: selle artikli autorid on insenerid väikesest Tšehhi ettevõttest pipetail. Neil õnnestus koostada suurepärane nimekiri [mõningatest triviaalsetest, kuid endiselt] nii aktuaalsetest probleemidest ja väärarusaamadest, mis on seotud Kubernetes klastri kasutamisega.

10 tüüpilist viga Kuberneteset kasutades

Aastate jooksul, mil oleme Kuberneteset kasutanud, oleme töötanud suure hulga klastritega (nii hallatud kui ka hallamata — GCP-s, AWS-is ja Azure'is). Aja jooksul oleme märganud, et teatud vead korduvad pidevalt. Kuid selles pole midagi häbiväärset: me oleme ise teinud enamik neist!

Artiklis on kokku kogutud kõige levinumad vead ning mainitud on ka, kuidas neid parandada.

1. Ressursid: päringud ja limiidid

See punkt väärib kindlasti kõige tähelepanelikumat tähelepanu ja esimest kohta nimekirjas.

CPU päring tavaliselt kas ei ole üldse määratud või on selle väärtus väga madal (et mahutada võimalikult palju pod'e igasse sõlme). Seetõttu saavad sõlmed ülekoormatud. Suure koormuse ajal on sõlme protsessorite võimsused täielikult kasutuses ning konkreetne töökoormus saab ainult seda, mida ta on "pärinud" läbi CPU trottlimise. See toob kaasa viivituste suurenemise rakenduses, ajutised katkestused ja teised ebameeldivad tagajärjed. (Lisainfot selle kohta leiate meie teisest hiljutisest tõlkest: "CPU piirangud ja agressiivne trottling Kuberneteses» — tõlk. märkus)

Parim Pingutus (väga ei soovitatav):

resources: {}

Äärmiselt madal CPU päring (väga ei soovitatav):

   resources
      Requests:
        cpu: "1m"

Teisest küljest võib CPU limiidi olemasolu põhjustada põhjendamatut taktsageduse langust pod'ide puhul, isegi kui sõlme protsessor ei ole täielikult koormatud. Taaskord, see võib viia viivituste suurenemiseni. Arutatakse endiselt parameetrit CPU CFS kvota Linuxi tuumas ja CPU trottlimist sõltuvalt määratud piiridest, samuti CFS kvota keelamist... Kahjuks võivad CPU limiidid tekitada rohkem probleeme, kui suudavad lahendada. Lisainfot selle kohta leiate allolevalt lingilt.

Liialdamine (overcommitting) mäluga võib viia ulatuslikumate probleemide tekkeni. CPU piiri saavutamine toob kaasa taktsageduse kaotuse, samas kui mälupiiri saavutamine toob kaasa pod'i "tapmise". Kas olete kunagi näinud OOMkill? Да, речь идет именно о нем.

Soovite selle sündmuse tõenäosust minimeerida? Ärge jagage ülemääraseid mälumahte ja kasutage Guaranteed QoS (teenuse kvaliteet), seades mälu päringu võrdseks piiriga (nagu allolevas näites). Lisainfot selle kohta leiate Henning Jacobsi esitlusest (Zalando juhtivinsener).

Purskamine (suurem tõenäosus saada OOMkilled):

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

Tagatud:

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

Mis võiks potentsiaalselt aidata ressursside seadistamisel?

Käesoleva abil metrics-server saab vaadata hetke CPU ja mälu kasutust pod'ide (ja nende sees olevate konteinerite). Tõenäoliselt kasutate seda juba. Lihtsalt käivitage järgmised käsklused:

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

Kuid need näitavad ainult hetke kasutust. Selle abil saab hinnanguliselt mõista suurusjärku, kuid lõpuks on vajalik mõõdikute ajaloo jälgimine (et vastata sellistele küsimustele nagu: "Mis oli CPU tippkoormus?", "Milline oli koormus eile hommikul?" — jne). Selleks võib kasutada Prometheus, DataDog ja teisi tööriistu. Need lihtsalt saavad mõõdikud metrics-server'ilt ja salvestavad need, ning kasutaja saab neid küsida ja vastavaid jooniseid koostada.

VerticalPodAutoscaler lubab saab automatiseerida seda protsessi. See jälgib protsessori ja mälukasutuse ajalugu ning seadistab uusi päringuid ja limiite selle teabe põhjal.

Tõhus arvutusvõimsuse kasutamine on keeruline ülesanne. See on nagu pidevalt tetrisemängu mängimine. Kui maksate liiga palju arvutusvõimsuse eest madala keskmise tarbimise juures (ütleme, ~10 %), soovitame vaadata AWS Fargate või Virtual Kubelet põhiseid tooteid. Need toimivad serverless/maksa kasutuse alusel mudelis, mis nendes tingimustes võib osutuda odavamaks.

2. Elujõudluse ja valmisoleku kontrollid

Vaikimisi ei ole Kuberneteses elujõudluse ja valmisoleku kontrollid aktiivsed. Ja mõnikord unustatakse need sisse lülitada...

Aga kuidas muidu võiks teenuse taaskäivitamist algatada, kui esineb lahendamatuid vigu? Ja kuidas koormuse tasakaalustaja teab, et mingi pod on valmis liiklust vastu võtma? Või et ta suudab töödelda rohkem liiklust?

Sageli segatakse neid kontrolle omavahel:

  • Elujõudlus — elujõudluse kontroll, mis taaskäivitab pod'i, kui see ebaõnnestub;
  • Valmidus — valmisoleku kontroll, mis katkestab pod'i Kubernetes teenusest, kui see ebaõnnestub (seda saab kontrollida käsklusega kubectl get endpoints) ja sellele ei suunata liiklust, kuni järgmine kontroll on edukalt lõpule viidud.

Mõlemad kontrollid TEGELETAKSE KÕIKIDE POD'I ELU ETAPPI JÄRGNATUD AEGADE KEELES. See on väga oluline.

Levinud eksiarvamus on, et readiness-proove käivitatakse ainult käivitamisel, et tasakaalustaja saaks teada, et pod on valmis (Valmis) ja saab alustada liikluse töötlemist. Kuid see on vaid üks võimalik rakendus.

Teine — teada saada, et liiklus pod'ile on liiga suur ja üles laadib selle (või pod viib läbi ressursimahuka arvutuse). Sellisel juhul aitab readiness-kontroll seda koormust vähendada ja "jahutada".Edasi liikudes võimaldab readiness-kontrolli edukas läbimine taas kasutada suuremat koormust pod'ile.. Sel juhul (kui readiness-proov nurjub) liveness-kontrolli ebaõnnestumine oleks väga ebatõhus. Miks taaskäivitada pod, mis on terve ja pingutab kõvasti?

Seetõttu on mõnel juhul täielik kontrollide puudumine parem kui vale seadistusega nende sisse lülitamine. Nagu ülal mainitud, kui liveness-kontroll kopeerib readiness-kontrolli,siis olete suures hädas. Üks variant on seadistada ainult readiness-test, ja ohtlik liveness jätta kõrvale.

Mõlemad kontrollitüübid ei tohi ebaõnnestuda, kui üldised sõltuvused ebaõnnestuvad, vastasel juhul toob see kaasa kaskaadi (laviinitaolise) kõikide pod'ide rikke. Teisisõnu, ärge kahjustage iseennast..

3. LoadBalancer iga HTTP-teenuse jaoks

Tõenäoliselt on teil klastris HTTP-teenuseid, mida soovite suunata välismaailma.

Kui avate teenuse kui type: LoadBalancer, siis selle kontrollija (teenuse pakkuja sõltuvalt) loob ja sõlmib välise LoadBalancer'i (mitte tingimata L7-l põhineva, pigem L4-l), ja see võib mõjutada kulusid (välise staatilise IPv4 aadressi, arvutusvõimsuse, sekunditariifide tõttu), kuna on vajalik luua suur hulk sarnaseid ressursse.

Sellisel juhul on mõistlikum kasutada ühte välist koormuse tasakaalijat, avades teenused kui type: NodePort.Või, mis veelgi parem, rakendada midagi sarnast nginx-ingress-controller (või traefik), mis toimib ainukesele NodePort lõpp-punktile, mis on seotud välise koormuse tasakaalijaga ja suunab kliendi liikluse klastris ingress-ressursside kaudu Kubernetes.

Teised klastrisisese (mikro)teenused, kes omavahel suhtlevad, saavad "suhelda" teenuste kaudu, mille tüüp on ClusterIP ja sisseehitatud teenuse tuvastamise mehhanismi kaudu DNS-i kaudu. Kuid ärge kasutage nende avalikke DNS/IP aadresse, kuna see võib mõjutada latentsust ja tõsta pilveteenuste hindu.

4. Klastri automaatskalaarimine, arvestamata selle eripärasid

Klastri sõlmede lisamisel ja eemaldamisel ei tasu tugineda mõningatele põhimetriikidele, nagu CPU kasutamine nende sõlmedes. Pod'i planeerimine peab arvestama paljusid piirangud, näiteks pod'ide/sõlmede lähedust, taints ja toleratsioone, ressursitaotlusi, QoS jne. Väline automaatne skaalaja, mis neid nüansse ei arvestanud, võib tekitada probleeme.

Kujutage ette, et mõni pod peab olema planeeritud, kuid kõik saadaval olevad CPU ressursid on nõutud/jaotatud ja pod jääb seisu Ootel. Väline automaatne skaalaja näeb keskmist praegust CPU koormust (mitte nõutud) ja ei alusta laiendamist (scale-out) - ei lisa veel ühte sõlme. Selle tulemusena ei planeerita antud pod'i.

Samas vastupidine масштабирование (scale-in) - sõlme eemaldamine klastrist - on alati keerulisem teostada. Kujutage ette, et teil on stateful pod (püsiv salvestus on ühendatud). Püsivad mahud kuuluvad tavaliselt kindlasse saadavuse tsooni ja ei replitseerita piirkonnas. Nii et kui väline automaatne skaalaja eemaldab sõlme koos selle pod'iga, ei saa planeerija seda pod'i teisele sõlmele planeerida, kuna see saab toimuda ainult selles saadavuse tsoonis, kus püsiv salvestus asub. Pod jääb kinni seisu Ootel.

. Kubernetes'i kogukonnas on suur populaarsus cluster-autoscaler. See töötab klastris, toetab põhiteenuste pakkujate API-sid, arvestab kõiki piiranguid ja oskab skaleerida eelmainitud juhtudel. Samuti suudab see teostada scale-in, säilitades kõik seatud piirangud, säästes raha (mida muidu kulutatakse kasutamata ressurssidele).

5. IAM/RBAC võimaluste ületamine

Olge ettevaatlik, et vältida IAM-kasutajate kasutamist püsivate saladustega masinate ja rakenduste jaoks.Korraldage ajutine juurdepääs, kasutades rolle ja teenuse kontosid (teenusekontod).

Me kohtame sageli olukordi, kus pääsukoodid (ja saladused) on rakenduse konfiguratsioonis "hardcode"-itud ning saladuste vahetust ignoreeritakse, hoolimata olemasolevast ligipääsust Cloud IAM-ile. Kasutage IAM-rolle ja teenusekontosid vältimaks kasutajate tegemist seal, kus see on asjakohane.

10 tüüpilist viga Kuberneteset kasutades

Unustage kube2iam ja minge kohe IAM-rolleteni teenusekonto jaoks (nagu on kirjeldatud samanimelises märkmes Š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

Üks annotatsioon. Mitte nii raske, eks?

Lisaks vältige teenusekontode ja instantsiprofiilide andmist õigustega admin ja cluster-admin, kui nad seda ei vaja. Selle rakendamine on natuke keerulisem, eriti K8si RBAC-s, kuid kindlasti tasub pingutust.

6. Ärge toetuge automaatsele anti-affinity pod’ide jaoks

Kujutage ette, et teil on kolm koopiat mingist deploy’mentist sõlmes. Sõlm langeb kokku, ja koos sellega kõik koopiad. Ebameeldiv olukord, eks? Aga miks kõik koopiad olid ühes sõlmes? Kas Kubernetes ei peaks tagama kõrget saadavust (HA)?!

Kahjuks Kubernetes ei kohustu iseenesest eraldi eksisteerimise reeglitele (anti-affinity) pod’ide jaoks. Need tuleb selgelt määratleda:

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

Nii lihtne see ongi. Nüüd plaanitakse pod’id erinevatele sõlmedele (see tingimus kontrollitakse ainult planeerimise ajal, mitte nende töötamise ajal — seetõttu requiredDuringSchedulingIgnoredDuringExecution).

Siin räägime sellest podAntiAffinity erinevates sõlmedes: topologyKey: "kubernetes.io/hostname", — mitte erinevates saadavuspiirkondades. Täieliku HA saavutamiseks tuleb sellel teemal rohkem kaevata.

7. PodDisruptionBudget’ide ignoreerimine

Kujutage ette, et teil on tootmiskoormus Kubernetes klastris. Perioodiliselt tuleb sõlmi ja kogu klastrit uuendada (või decommissionida). PodDisruptionBudget (PDB) on midagi nagu garantii teenusevahekohtuks klastrihaldurite ja kasutajate vahel.

PDB aitab vältida teenuste töös häireid, mille põhjustavad sõlmede puudumine:

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

Selles näites ütlete teie, kui klastrikasutaja, halduritele: "Hei, mul on zookeeper teenus, ja sõltumata sellest, mida teete, soovin, et vähemalt 2 selle teenuse koopiat oleks alati kergesti saadaval."

Rohkem sellest saate lugeda siit.

8. Mitmed kasutajad või keskkonnad ühises klastris

Kubernetes'i nimed (namespaces) ei paku tugevat eraldusvõimet..

Levinud on vale arusaam, et kui käivitada mitte-prod koormus ühes nimes, ja prod koormus teises, siis nad ei mõjuta üksteist mingil moel… Siiski võib teatud taseme eraldusvõimet saavutada ressursside päringute/piirangute, kvota seadistamise ja priorityClass’ide määramise abil. Teatud "füüsilist" eraldusvõimet data plane’is tagavad affinities, tolerations, tainted (või nodeselectors), kuid sarnase eraldamise saavutamine on pigem keeruline rakendada.

Need, kes peavad mõlemat tüüpi töökoormusi ühes klastris koostama, peavad keerukusega leppima. Kui sellist vajadust ei ole ja teil on võimalik luua veel üks klaster (ütleme, avalikus pilves), siis on parem seda teha. See võimaldab saavutada oluliselt kõrgemat eraldusvõimet.

9. externalTrafficPolicy: Cluster

Me näeme sageli, et kogu liiklus klastrisse siseneb NodePort tüüpi teenuse kaudu, millel on vaikimisi seadistatud poliitika externalTrafficPolicy: Cluster. See tähendab, et NodePort see on avatud igas klastris asuvas sõlmes, ja neid saab kasutada, et suhelda vajaliku teenusega (pod’ide komplektiga).

10 tüüpilist viga Kuberneteset kasutades

Samal ajal asuvad tegelikud pod’id, mis on seotud eeltoodud NodePort teenusega, tavaliselt ainult mõnes selle sõlme allkogumis.Teisisõnu, kui ma ühendan sõlmega, kus ei ole vajalikke pod’e, suunatakse see liiklus teisele sõlmele, lisades ülekande etapi (hop) ja suurendades latentsust (kui sõlmed asuvad erinevates saadavuspiirkondades/data keskustes, võib latentsus olla üsna kõrge; lisaks tõusevad egress-liikluse kulud).

Teisest küljest, kui mingile Kubernetes'i teenusele on määratud poliitika externalTrafficPolicy: Local, avatakse NodePort ainult nendel sõlmedel, kus on tegelikult käimas vajalikud pod’id. Kui kasutatakse väliseid koormuse tasandi seadmeid, mis kontrollib olekute (healthchecking) lõpp-punkte (nagu teeb AWS ELB), sa suunad liiklust ainult vajalikesse sõlmedesse, mis positiivselt mõjutab latentsust, arvutusnõudmisi, egressi arve (ja mõistlik mõte ütleb sama).

On suur tõenäosus, et kasutate juba midagi sarnast traefik või nginx-ingress-controller NodePort-punktina (või LoadBalancer, mis samuti kasutab NodePort) määramine HTTP ingress-liikluse suunamiseks võib oluliselt vähendada viivitust sarnaste päringute puhul.

V selles publikatsioonis saate rohkem teada externalTrafficPolicy, selle eelistest ja puudustest.

10. Ärge siduge klastreid ja ärge kuritarvitage juhtimistasandit

Varasemalt nimetati servereid isiklike nimede järgi: Anton, HAL9000 ja Colossus… Täna on nende asemel juhuslikult genereeritud identifikaatorid. Kuid harjumus on alles jäänud ja nüüd saavad isiklikud nimed klastrid.

Tüüpiline lugu (põhineb tõsielul): kõik algas konseptsiooni tõestamisest, seega kandis klaster uhket nime testing… Aastad on möödunud ja seda KASUTATAKSE SIIA MAANI tootmises, ja kõik kardavad selle kallale minna.

Klastrite muutmine lemmikuteks ei ole naljakas, seega soovitame neid aeg-ajalt eemaldada, samal ajal harjutades katastroofidest taastumist (seda aitab chaos engineering — kt. tõlge). Samuti ei tee paha tegeleda juhtimistasandiga (control plane). Hirm selle kallale minna — ei ole just hea märk. Etcd surnud? Poisid, olete tõeliselt mütsiga üle pea läinud!

Teisest küljest, ära liialda selle käsitlemisega. Aja jooksul juhtimistasand võib muutuda aeglaseks.Tõenäoliselt on see tingitud suurtest objektide hulkadest ilma nende rotatsioonita (tavaline olukord Helmiga vaikeseadistustes, mille tõttu ei uuendata selle olekut configmap'ides/ saladustes — tulemuseks on see, et juhtimistasandale koguneb tuhandeid objekte) või pidevast objektide redigeerimisest kube-api's (automaatselt skaleerimiseks, CI/CD, jälgimiseks, sündmuste logimiseks, kontrollijate jne jaoks).

Samuti soovitame kontrollida SLA/SLO kokkuleppeid hallatava Kubernetes-teenuse pakkujaga ja pöörata tähelepanu garantii tingimustele. Teenusepakkuja võib garanteerida juhtimistasandi kättesaadavuse (või selle alamkomponente), kuid mitte p99-päringute viivitust, mida saadate. Teisisõnu, saate saata kubectl get nodes, kuid vastust võite oodata kuni 10 minutit, ja see ei ole teenuse tasandi kokkuleppe rikkumine.

11. Boonus: viimane silt kasutamine

See on juba klassika. Viimasel ajal ei ole me sellise tehnikaga enam sageli kokku puutunud, kuna paljud, kes on kogenud karmi kogemust, on lõpetanud sildi :latest kasutamise ja hakanud versioone kinnitama. Hooray!

ECR toetab siltide muutumatust; soovitame tutvuda selle tähelepanuväärse funktsiooniga.

Kokkuvõte

Ärge lootke, et kõik töötab hetkega: Kubernetes ei ole imerohi. Halvasti kirjutatud rakendus jääb selliseks isegi Kuberneteses (ja võib-olla muutub veel hullemaks). Ükskõiksus viib liigse keerukuse, aeglase ja pingelise juhtimistasandini. Lisaks riskite jääda ilma hädaolukorra taastamise strateegiata. Ärge lootke, et Kubernetes "karbist väljas" piisavalt hoolitseb isoleerimise ja kõrge kättesaadavuse eest. Veetke veidi aega, et teha oma rakendus tõeliselt pilvepõhiseks.

Erinevate meeskondade ebaõnnestumistega tutvumiseks vaadake seda kogumikku lugusid Henning Jacobsilt.

Need, kes soovivad täiendada seda asjaolu loetelu, võivad meiega Twitteris ühendust võtta (@MarekBartik, @MstrsObserver).

P.S. tõlkija märkused

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster