10 tüüpilist viga Kubernetes'i kasutamisel

Märkus tõlke kohta.: Artikli autorid on insenerid väikesest Tšehhi ettevõttest pipetail. Neil õnnestus koguda tähelepanuväärne nimekiri [kohtadest, mis on mõnes mõttes banaalsed, kuid siiski] nii olulistest probleemidest ja eksiarvamustest, mis on seotud Kubernetesi klastrite kasutamisega.

10 tüüpilist viga Kubernetes'i kasutamisel

Kuna oleme Kubernetesit aastaid kasutanud, oleme töötanud paljude klastritega (nii hallatud kui ka hallamata - GCP, AWS ja Azure platvormidel). Aja jooksul oleme märganud, et teatud vead korduvad pidevalt. Kuid siin pole midagi häbiväärset: me oleme ise teinud enamik neist!

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

1. Ressursid: päringud ja piirangud

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

CPU päring tavaliselt kas üldse ei ole määratud või on see väga madal (et mahutada võimalikult palju pod'e igasse sõlme). Seetõttu on sõlmed ülekoormatud. Suure koormuse korral on sõlme protsessorivõimsused täielikult kasutusel ja konkreetne töökoormus saab vaid seda, mida ta on 'pärinud' läbi CPU trottle'imise.See toob kaasa viivituste suurenemise rakenduses, ajatahud ja muid ebameeldivaid tagajärgi. (Lisaks tutvuge meie teise hiljutise tõlkega: 'CPU-limiidid ja agressiivne throttling Kubernetes'is» — tõlkija märkus)

BestEffort (äärmiselt ei soovitatav):

resources: {}

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

   resources:
      Requests:
        cpu: "1m"

Teisest küljest võib CPU piirangute olemasolu põhjustada põhjendamatut pod'ide tsüklite vahelejätmist, isegi kui sõlme protsessor ei ole täielikult koormatud. Taas, see võib viia viivituste suurenemiseni. Arutelu CPU CFS kvota üle Linuxi tuumas ja CPU trottle'imise alusel kehtestatud piirangute ning CFS kvota eemaldamise üle jätkub... Kahjuks võivad CPU piirangud põhjustada rohkem probleeme, kui nad suudavad lahendada. Lisainfot selle kohta leiate allolevalt lingilt. Liigne jaotamine (overcommitting)

mälu võib põhjustada suuremaid probleeme. CPU piiri saavutamine toob kaasa tsüklite vahelejätmise, samas kui mälu piiri saavutamine toob kaasa pod'i 'tapmise'. Kas olete kunagi näinud OOMkill mälu võib põhjustada suuremaid probleeme. CPU piiri saavutamine toob kaasa takti vahelejätmise, samas kui mälu piiri saavutamine toob kaasa pod'i "tapmise". Olete kunagi märganud OOMkill? Да, речь идет именно о нем.

Kas soovite vähendada selle sündmuse tõenäosust? Ärge jaotage liialt mälu ja kasutage Guaranteed QoS (Quality of Service), seadistades memory request-i võrdseks limiidiga (nagu allolevas näites). Rohkem teavet selle kohta leiate Henning Jacobsi esitlusest (Zalando peainsener).

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

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

Guaranteed:

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

Mis võiks aidata ressursside seadistamisel?

EL-i abil metrics-server saate vaadata podide (ja nende sees olevate konteinerite) praeguseid CPU ja mälu kasutuse näitajaid. Tõenäoliselt kasutate neid juba. Lihtsalt täitke järgmised käsud:

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

Kuid need näitavad ainult praegust kasutust. Selle abil saate ligikaudse ülevaate suurusjärgust, kuid lõpuks on vajalik meetrika ajaloos muutumine (et vastata sellistele küsimustele nagu: „Milline oli CPU tipukoormus?“, „Milline oli koormus eile hommikul?“ jne.). Selle jaoks saate kasutada Prometheus, DataDog ja muid tööriistu. Need saadavad lihtsalt metrikad metrics-server'ilt ja salvestavad need, ning kasutaja saab neid küsida ja vastavad graafikud joonistada.

VerticalPodAutoscaler kaugelt sulgeda vahekaarte, mis on avatud teistel seadmetel. automatiseerida seda protsessi. See jälgib protsessori ja mälu kasutamise ajalugu ning seadistab uusi request'e ja limiite selle teabe põhjal.

Tõhus arvutusvõimsuse kasutamine on keeruline ülesanne. See on nagu pidev tetris. Kui maksate liiga palju arvutusvõimsuse eest madala keskmise kasutuse korral (ütleme, ~10 %), siis soovitame uurida AWS Fargate või Virtual Kubelet tooteid. Need on üles ehitatud serverless/pay-per-usage arve mudelile, mis sellistes tingimustes võib olla soodsam.

2. Liveness ja readiness probes

Kuberneteses ei ole vaikimisi liveness ja readiness kontrollid sisse lülitatud. Ja vahel unustatakse need sisse lülitada...

Aga kuidas muidu võiks teenuse taaskäivitamist algatada, kui esineb lahendamatud vead? Ja kuidas koormustasakaalustaja saab teada, et mõni pod on valmis liiklust vastu võtma? Või et ta suudab hallata rohkem liiklust?

Need proovid segatakse sageli omavahel:

  • Elujõudlus — eluasemete kontroll, mis taaskäivitab pod'i, kui see lõpetab töö ebaõnnestunult;
  • Valmidus — valmiduse kontroll, mis katkestab pod'i ühenduse Kubernetes teenusega (seda saab kontrollida kasutades kubectl get endpoints) ja liiklus ei jõua selleni kuni järgmine kontroll ei õnnestu.

Mõlemad kontrollid TOIMIVAD KOGU POD'I ELU CYCLE'I AEG,. See on väga oluline.

Levinud eksiarvamus on, et valmiduse proovide käivitamine toimub ainult alustamisel, et koormuse tasakaalustaja oskaks ära tunda, et pod on valmis (Valmis) ja saab alustada liikluse töötlemist. Kuid see on vaid üks nende kasutamise võimalustest.

Teiseks — võimalus näha, et pod'ile tuleb liiga suur liiklus ja see ületab selle võimekuse (või pod teostab ressursinõudlikke arvutusi). Sellisel juhul aitab valmiduse kontroll alandada pod'i koormust ja "jahutada" seda. Valmiduse kontrolli edukas läbimine tulevikus võimaldab jälle koormust suurendada pod'ile. Sellisel juhul (kui valmiduse proov ebaõnnestub) liveness proovide ebaõnnestumine oleks väga kahjulik. Miks taaskäivitada pod, mis on terve ja töötab igasuguse vaeva alla?

Seetõttu on mõnel juhul parem, kui kontrollid puuduvad, kui nende aktiveerimine valesti seadistatud parameetritega. Nagu eelnevalt mainitud, kui liveness kontroll kopeerib valmiduse kontrolli, siis olete suures hädas. Üks võimalus on seadistada ainult valmiduse test, vaid jähtunud livenessi jätta kõrvale.

Mõlemad kontrolli tüübid ei tohi ebaõnnestuda, kui üldised sõltuvused langevad, vastasel juhul toob see esile kaskaadse (lumepallitaolise) ebaõnnestumise kõigis pod'ides. Teisisõnu, ärge kahjustage ennast.

3. LoadBalancer iga HTTP-teenuse jaoks

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

Kui avada teenus kui tüüp: LoadBalancer, siis tema juht on (olenevalt teenusepakkujast) välistama ja kooskõlastama välist LoadBalancerit (mitte tingimata töötama L7-l, pigem L4-l), mis võib mõjutada kulusid (välise staatilise IPv4-aadresse, arvutusvõimsus, sekundipõhine arveldamine) seoses vajadustega luua hulga selliseid ressursse.

Sel juhul on mõistlikum kasutada ühte välist koormuse tasakaalustajat, avades teenuseid kui tüüp: NodePort. Või, mis veel parem, rakendada midagi nagu nginx-ingress-controller (või traefik), mis on ainus NodePort lõpp-punkt, mis on seotud välise koormuse tasakaalustajaga ja suunab liiklust klastris ingress-ressursside Kubernetes.

Teised klasterisisese (mikro)teenused, mis omavahel suhtlevad, saavad "suhelda" teenustega nagu ClusterIP ja teenuste avastamise sisseehitatud mehhanism DNS-i kaudu. Ärge kasutage nende avalikke DNS/iP, kuna see võib mõjutada latentsust ja viia pilveteenuste kulude kasvu.

4. Klasteri automaatne skaleerimine, arvestamata selle omadusi

Klastri sõlmede lisamisel ja eemaldamisel ei tohiks toetuda mõnedesse baasmõõdikutesse, nagu CPU kasutamine nendel sõlmedel. Pod'i kavandamine peab toimuma arvestades mitmeid piirangud, nagu pod'i/sõlmede affinity, taints ja tolerations, ressursside nõudmised, QoS jne. Välist autoskaleri kasutamine, mis ei arvestada neid nüansse, võib põhjustada probleeme.

Kujutage ette, et mingit pod'i tuleb planeerida, kuid kõik saadaval olevad CPU ressursid on nõutud/ära jagatud ja pod jääb seisma Pending. Väline autoscaler näeb keskmist praegust CPU koormust (mitte nõutud) ja ei alusta laiendamist (scale-out) – ei lisa veel ühte sõlme. Seetõttu ei ole see pod õigesti planeeritud.

Samas on vastupidine skaleerimine (scale-in) – sõlme eemaldamine klastrist – alati keerulisem ellu viia. Kujutage ette, et teil on stateful pod (ühendatud püsiva salvestusruumiga). Püsivad mahtu kuuluvad tavaliselt mingisse kättesaadavuse tsooni ja neid ei replitseerita regioonis. Seega, kui väline autoscaler eemaldab sõlme koos selle pod'iga, ei saa planeerija planeerida seda pod'i teisele sõlmele, kuna seda saab teha ainult seal, kus asub püsiv salvestusruum. Pod jääb seisma Pending.

Kubernetes'i kogukonnas on suur populaarsus cluster-autoscaler. See töötab klastris, toetab API-d peamiste pilveteenuste pakkujatega, arvestab kõiki piiranguid ja oskab skaleerida eelpoolnimetatud juhtudel. Samuti on tal võime scale-in, säilitades kõik seatud piirangud, säästes raha (mida oleks muidu kulutatud kasutamata ressursside peale).

5. IAM/RBAC võimaluste alahindamine

Ole ettevaatlik IAM-kasutajate kasutamisega, kellel on püsivad saladused masinate ja rakendused. Korraldage ajutine juurdepääs, kasutades rolle ja teenusekontosid (teenusekontod).

Kolegelt tihti seisame silmitsi olukorraga, kus pääsukoodid (ja saladused) on ‘hardcode’itud rakenduse konfiguratsiooni, samuti hoolimatusega saladuste rotatsiooni suhtes, kuigi Cloud IAM-ile on juurdepääs olemas. Kasutage IAM rolle ja teenusekontoid mitte kasutajaid, kui see on asjakohane.

10 tüüpilist viga Kubernetes'i kasutamisel

Unustage kube2iam ja minge kohe üle IAM rollidele teenusekontode jaoks (nagu kirjeldatakse samanimelises märkuses Š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 märkus. Ei ole sugugi keeruline, eks?

Lisaks, ärge andke teenusekontodele ja instantsiprofiilidele õigusi admin ja cluster-admin, kui nad seda ei vaja. Selle teostamine on veidi keerulisem, eriti K8s RBAC-is, kuid kindlasti on see pingutust väärt.

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

Kujutage ette, et teil on kolm koopiat mõnest deploy'mendist sõlmes. Sõlm sureb ja koos sellega kõik koopiad. Ebameeldiv olukord, eks? Aga miks kõik koopiad olid ühes sõlmes? Kas Kubernetes ei peaks tagama kõrge kättesaadavuse (HA)?!

Kahjuks ei järgita Kubernetes'i plaanija iseseisvalt pod'ide eraldi eksisteerimise reegleid. (anti-affinity) Need tuleb selgelt kirja panna:

// опущено для краткости
      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 plaanimisel, kuid mitte nende töö ajal — seetõttu requiredDuringSchedulingIgnoredDuringExecution).

Siin räägime podAntiAffinity erinevates sõlmedes: topologyKey: "kubernetes.io/hostname", — mitte erinevates kättesaadavuse tsoonides. Tõeliselt täiustatud HA saavutamiseks tuleb selle teema kallale minna sügavamale.

7. PodDisruptionBudget'ide ignoreerimine

Kujutage ette, et teil on tootmiskoormus Kubernetes'i klastris. Perioodiliselt tuleb sõlmede ja kogu klastri uuendamist (või väljaarendamist). PodDisruptionBudget (PDB) on nagu garantiileping teenuste haldajate ja kasutajate vahel.

PDB aitab vältida teenuste katkestusi, mis tulenevad sõlmede puudusest:

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

Selles näites teatate te klastrikasutajana administreerijatele: "Hei, mul on zookeeper teenus ja ükskõik, mida te teete, soovin, et vähemalt 2 selle teenuse koopiat oleks alati saadaval."

Lisainfot selle kohta võib lugeda siin.

8. Mitmed kasutajad või keskkonnad ühes ühises klastris

Kubernetes'i nimed (namespaces) ei taga tugevat eraldatust.

On levinud eksiarvamus, et kui käivitada mitte-prod koormus ühes nimes, ja prod koormus teises, siis need ei mõjuta üksteist.… Kuid mingit eraldatuse taset on võimalik saavutada ressursside päringute/piirangute, kvootide seadistamise, priorityClasside määramise abil. Teatud "füüsilise" eraldatuse tagavad andmeplaani puhul affinities, tolerations, taints (või nodeselectors), kuid selline eraldamine on üsna keeruline rakendada.

Need, kes peavad kahte töökoormust ühes klastris kombineerima, peavad leppima keerukusega. Kui sellist vajadust ei ole ja teil on võimalus luua veel üks klaster (ütleme, avalikus pilves), siis on parem see teha. See võimaldab saavutada palju kõrgemat eraldatuse taset.

9. externalTrafficPolicy: Cluster

Väga tihti näeme, et kogu klastrisse sisenenud liiklus läheb läbi NodePort tüüpi teenuse, millel on vaikimisi seadistus externalTrafficPolicy: Cluster. See tähendab, et NodePort see on avatud iga sõlme peal klastris ja võite kasutada ühte neist selle vajaliku teenusega (podide komplektiga) suhtlemiseks.

10 tüüpilist viga Kubernetes'i kasutamisel

Samas on tõelised podid, mis on seotud ülalmainitud NodePort teenusega, tavaliselt vaid mingil alamhulgal neist sõlmedest.Teisisõnu, kui ma ühinen sõlmega, kus vastavat pod'i pole, suunab see liikluse teisele sõlmele, lisades vahepealse etapi (hop) ja suurendades latentsust (kui sõlmed asuvad erinevates saadavuspiirkondades/datakeskustes, võib latentsus olla üsna kõrge; samuti suureneb väljamineva liikluse hind).

Teisest küljest, kui mingile Kubernetes'i teenusele on määratud poliitika externalTrafficPolicy: Local, siis NodePort avatakse ainult nendel sõlmedel, kus tegelikult on käivitatud vajalikud podid. Kui kasutada väljastpoolt koormuse tasakaalustajat, mis kontrollib (healthchecking) lõpp-punkte (nagu teeb AWS ELB), siis suunab see liikluse ainult vajalikule sõlmele., mis see soodustab latentsust, arvutusvajadusi, egressi arve (ja ka tervemõistus ütleb sama).

On suur tõenäosus, et kasutate juba midagi sellist nagu traefik või nginx-ingress-controller lõpp-punktina NodePort (või LoadBalancer, mis samuti kasutab NodePort) HTTP sisenemisliikluse suunamiseks, ning selle valiku seadmine võib oluliselt vähendada selliste päringute latentsust.

Uues selle väljaande võite täpsemalt teada saada externalTrafficPolicy-st, selle eelistest ja puudustest.

10. Ärge seostage klastreid ning ärge kuritarvitage juhtimistasandit

Varem nimetati servereid isikunimedega: Anton, HAL9000 ja Colossus… Täna on nende asemel juhuslikult genereeritud tuvastused. Kuid harjumus on jäänud ning nüüd antakse isikunimed klastritele.

Tüüpiline lugu (põhineb tõelistel sündmustel): kõik algas kontseptsiooni tõestamisest, seega kandis klaster uhket nime testimine… Aastad on möödunud ja see on KUNI NÜÜD välja toodud tootmises ning kõik kardavad seda puudutada.

Pole midagi naljakat selles, et klastrid muutuvad lemmikuteks, seega soovitame neid perioodiliselt kustutada, samal ajal harjutades katastroofijärgset taastumist (selles aitab chaos engineering — toimetaja märkus). Lisaks ei tee haiget tegeleda ka juhtimistasandiga (control plane). Hirm seda puudutada — ei ole just hea märk. Etcd surnud? Poisid, olete tõeliselt mures!

Teisest küljest, ei tasu sellega liialdada. Aja jooksul juhtimistasand võib aeglustuda.Tõenäoliselt on see tingitud suurest kogusest loodud objektidest ilma nende rotatsioonita (tavaline olukord, kui kasutatakse Helm-i vaikeseadetest, mis ei uuenda selle seisundit configmap'ides/sekreedes — tulemuseks on juhtimistasandale kogunenud tuhandeid objekte) või pidevast objektide redigeerimisest kube-api-s (automaatse skaleerimise, CI/CD, jälgimise, sündmuste logimise, kontrollerite jne jaoks).

Lisaks soovitame kontrollida SLA/SLO kokkuleppeid hallatud Kubernetes tarnijaga ning pöörata tähelepanu garantiidele. Tarnija võib garanteerida juhtimistasandi kättesaadavuse (või selle alakomponentide), kuid mitte p99-päringute latentsust, mida talle saadate. Teisisõnu, võite sisse viia kubectl get nodes, ja vastuse saamine alles 10 minuti pärast ei ole teenuselepingu tingimuste rikkumine.

11. Boonus: uusima sildi kasutamine

See on juba klassika. Viimasel ajal ei kohtu me sellise tehnikaga nii tihti, kuna paljud, kes on kogenud kibedaid kogemusi, on lõpetanud sildi kasutamise : uusim ja hakkasid versioone kinnitama. Hurraa!

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

Elulookirjeldus

Ärge oodake, et kõik tööle hakkab nagu nõiavitsaga: Kubernetes ei ole panaceum. Halb rakendus jääb selliseks isegi Kuberneteses (ja võib-olla saab isegi hullemaks). Ükskõiksus viib ülemäärase keerukuse, aeglase ja pingelise halduskihi tööni. Lisaks riskite jääda ilma hädaabi strateegiata. Ära oota, et Kubernetes "karbist välja" tagab isoleerituse ja kõrge kättesaadavuse. Kulutage natuke aega, et muuta oma rakendus tõeliselt cloud native.

Mitmete meeskondade ebaõnnestunud kogemustega tutvumiseks saab vaadata seda kogumikku lugusid Henning Jacobsi poolt.

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

P.S. tõlkijalt

Lugege ka meie blogist:

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster