10 běžných chyb při používání Kubernetes

Poznámka. přel.: Autory tohoto článku jsou inženýři z malé české firmy pipetail. Podařilo se jim dát dohromady úžasný seznam [někdy banálních, ale stále] velmi naléhavých problémů a mylných představ souvisejících s provozem clusterů Kubernetes.

10 běžných chyb při používání Kubernetes

Za léta používání Kubernetes jsme pracovali s velkým množstvím clusterů (spravovaných i nespravovaných – na GCP, AWS a Azure). Postupem času jsme si začali všímat, že se některé chyby neustále opakují. Není to však žádná ostuda: většinu z nich jsme udělali sami!

Článek obsahuje nejčastější chyby a také zmiňuje, jak je opravit.

1. Zdroje: požadavky a limity

Tato položka si rozhodně zaslouží největší pozornost a první místo na seznamu.

Obvykle požadavek CPU buď není specifikován vůbec, nebo má velmi nízkou hodnotu (umístit co nejvíce podů na každý uzel). Dochází tak k přetížení uzlů. V době vysoké zátěže je výpočetní výkon uzlu plně využit a konkrétní zátěž přijímá pouze to, co si „vyžádala“ škrcení CPU. To vede ke zvýšené latenci aplikací, časovým limitům a dalším nepříjemným následkům. (Přečtěte si o tom více v našem dalším nedávném překladu: “Limity CPU a agresivní omezování v Kubernetes"- Cca. překlad.)

BestEffort (velmi ne doporučeno):

resources: {}

Extrémně nízký požadavek na CPU (extrémně ne doporučeno):

   resources:
      Requests:
        cpu: "1m"

Na druhou stranu přítomnost limitu CPU může vést k nepřiměřenému přeskakování hodinových cyklů moduly, i když procesor uzlu není plně zatížen. Opět to může vést ke zvýšeným zpožděním. Kolem parametru pokračují spory Kvóta CPU CFS v linuxovém jádře a omezování CPU v závislosti na nastavených limitech, stejně jako deaktivace kvóty CFS... Bohužel, limity CPU mohou způsobit více problémů, než mohou vyřešit. Více informací o tomto naleznete na níže uvedeném odkazu.

Přílišný výběr (převažující) problémy s pamětí mohou vést k větším problémům. Dosažení limitu CPU znamená přeskakování hodinových cyklů, zatímco dosažení limitu paměti znamená zabití modulu. Pozorovali jste někdy OOMkill? Ano, to je přesně to, o čem mluvíme.

Chcete minimalizovat pravděpodobnost, že se to stane? Nepřidělujte nadměrně paměť a používejte zaručenou QoS (Quality of Service) nastavením požadavku na paměť na limit (jako v příkladu níže). Přečtěte si o tom více v Prezentace Henninga Jacobse (vedoucí inženýr Zalando).

Prasknutí (vyšší šance na získání OOMkilled):

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

Garantovaná:

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

Co potenciálně pomůže při nastavování zdrojů?

S metrics-server můžete vidět aktuální spotřebu prostředků CPU a využití paměti moduly (a kontejnery v nich). S největší pravděpodobností jej již používáte. Stačí spustit následující příkazy:

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

Zobrazují však pouze aktuální využití. Může vám poskytnout hrubou představu o řádové velikosti, ale nakonec budete potřebovat historie změn metrik v průběhu času (pro zodpovězení otázek jako: „Jaké bylo maximální zatížení CPU?“, „Jaké bylo zatížení včera ráno?“ atd.). K tomu můžete použít Prometheus, DataDog a další nástroje. Jednoduše získají metriky z metrics-serveru a uloží je a uživatel se na ně může dotazovat a podle toho je vykreslovat.

VerticalPodAutoscaler umožňuje automatizovat tento proces. Sleduje historii využití CPU a paměti a na základě těchto informací nastavuje nové požadavky a limity.

Efektivní využití výpočetního výkonu není snadný úkol. Je to jako hrát Tetris pořád. Pokud platíte příliš mnoho za výpočetní výkon s nízkou průměrnou spotřebou (řekněme ~10 %), doporučujeme podívat se na produkty založené na AWS Fargate nebo Virtual Kubelet. Jsou postaveny na fakturačním modelu bez serveru/platby za použití, který se v takových podmínkách může ukázat jako levnější.

2. Sondy živosti a připravenosti

Ve výchozím nastavení nejsou v Kubernetes povoleny kontroly živosti a připravenosti. A někdy je zapomenou zapnout...

Ale jak jinak můžete spustit restart služby v případě fatální chyby? A jak nástroj pro vyrovnávání zatížení ví, že modul je připraven přijmout provoz? Nebo že zvládne větší provoz?

Tyto testy jsou často vzájemně zaměňovány:

  • Živost — kontrola „přežití“, která restartuje modul, pokud selže;
  • Připravenost — kontrola připravenosti, pokud selže, odpojí pod od služby Kubernetes (to lze zkontrolovat pomocí kubectl get endpoints) a provoz k němu nedorazí, dokud nebude úspěšně dokončena další kontrola.

Obě tyto kontroly PROVÁDĚNO BĚHEM CELÉHO ŽIVOTNÍHO CYKLU PODU. Je to velmi důležité.

Obvyklá mylná představa je, že sondy připravenosti jsou spuštěny pouze při spuštění, takže balancer může vědět, že modul je připraven (Ready) a může začít zpracovávat provoz. Je to však pouze jedna z možností jejich využití.

Další je možnost zjištění, že provoz na podu je nadměrný a přetěžuje to (nebo modul provádí výpočty náročné na zdroje). V tomto případě pomáhá kontrola připravenosti snižte zatížení podu a „zchlaďte jej“.. Úspěšné dokončení kontroly připravenosti v budoucnu umožňuje znovu zvyšte zatížení podu. V tomto případě (pokud test připravenosti selže) by selhání testu živosti bylo velmi kontraproduktivní. Proč restartovat pod, který je zdravý a tvrdě pracuje?

V některých případech je proto lepší vůbec žádné kontroly, než je povolit s nesprávně nastavenými parametry. Jak je uvedeno výše, pokud kontrola živosti kopie kontrola připravenosti, pak máte velký problém. Možnou možností je konfigurace pouze test připravenostia nebezpečná živost nechat stranou.

Oba typy kontrol by neměly selhat, když běžné závislosti selžou, jinak to povede ke kaskádovému (lavinovému) selhání všech modulů. Jinými slovy, neubližuj si.

3. LoadBalancer pro každou službu HTTP

S největší pravděpodobností máte ve svém clusteru služby HTTP, které byste chtěli přeposlat do vnějšího světa.

Pokud otevřete službu jako type: LoadBalancer, jeho řadič (v závislosti na poskytovateli služeb) poskytne a vyjedná externí LoadBalancer (nemusí nutně běžet na L7, ale dokonce i na L4), což může ovlivnit náklady (externí statická adresa IPv4, výpočetní výkon, účtování za sekundu ) kvůli potřebě vytvořit velké množství takových zdrojů.

V tomto případě je mnohem logičtější použít jeden externí load balancer, otevírající služby jako type: NodePort. Nebo ještě lépe, rozšířit něco jako nginx-ingress-controller (nebo traefik), který bude jediný Port uzlu koncový bod spojený s externím nástrojem pro vyrovnávání zatížení a bude směrovat provoz v clusteru pomocí vniknutí-Prostředky Kubernetes.

Jiné vnitroklastrové (mikro)služby, které na sebe vzájemně působí, mohou „komunikovat“ pomocí služeb jako ClusterIP a vestavěný mechanismus zjišťování služeb prostřednictvím DNS. Jen nepoužívejte jejich veřejné DNS/IP, protože to může ovlivnit latenci a zvýšit náklady na cloudové služby.

4. Automatické škálování clusteru bez zohlednění jeho vlastností

Při přidávání uzlů do clusteru a jejich odebírání z clusteru byste se neměli spoléhat na některé základní metriky, jako je využití procesoru v těchto uzlech. Plánování lusku musí vzít v úvahu mnohé omezení, jako je afinita pod/uzlů, skvrny a tolerance, požadavky na zdroje, QoS atd. Použití externího automatického škálovače, který nezohledňuje tyto nuance, může vést k problémům.

Představte si, že by měl být naplánován určitý modul, ale je požadován/rozebrán veškerý dostupný výkon CPU a modul uvízne ve stavu Pending. Externí autoscaler vidí průměrné aktuální zatížení CPU (nikoli požadované) a nezahájí expanzi (škálování) - nepřidá další uzel. V důsledku toho nebude tento modul naplánován.

V tomto případě obrácené měřítko (měřítko) — odstranění uzlu z klastru je vždy obtížnější implementovat. Představte si, že máte stavový modul (s připojeným trvalým úložištěm). Trvalé svazky obvykle patří konkrétní zónu dostupnosti a nejsou v regionu replikovány. Pokud tedy externí autoscaler odstraní uzel s tímto podem, plánovač nebude schopen naplánovat tento pod na jiném uzlu, protože to lze provést pouze v zóně dostupnosti, kde se nachází trvalé úložiště. Pod bude zaseknutý ve stavu Pending.

Velmi populární v komunitě Kubernetes cluster-autoscaler. Běží na clusteru, podporuje API od hlavních cloudových poskytovatelů, zohledňuje všechna omezení a může se ve výše uvedených případech škálovat. Je také schopen škálovat při zachování všech nastavených limitů, čímž šetří peníze (které by jinak byly vynaloženy na nevyužitou kapacitu).

5. Zanedbávání schopností IAM/RBAC

Dejte si pozor na používání uživatelů IAM s trvalými tajemstvími pro stroje a aplikace. Uspořádejte dočasný přístup pomocí rolí a servisních účtů (servisní účty).

Často se setkáváme s tím, že přístupové klíče (a tajné klíče) jsou pevně zakódovány v konfiguraci aplikace, stejně jako zanedbávání rotace tajných klíčů navzdory tomu, že máte přístup do Cloud IAM. Tam, kde je to vhodné, používejte místo uživatelů role a účty služeb IAM.

10 běžných chyb při používání Kubernetes

Zapomeňte na kube2iam a přejděte přímo k rolím IAM pro servisní účty (jak je popsáno v poznámka stejného jména Š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

Jedna anotace. Není to tak těžké, že?

Rovněž neudělujte oprávnění účtům služeb a profilům instancí admin и cluster-adminpokud to nepotřebují. To je trochu obtížnější implementovat, zejména v RBAC K8, ale rozhodně stojí za námahu.

6. Nespoléhejte na automatickou antiafinitu pro lusky

Představte si, že máte na uzlu tři repliky nějakého nasazení. Uzel padá a spolu s ním všechny repliky. Nepříjemná situace, že? Ale proč byly všechny repliky na stejném uzlu? Nemá Kubernetes poskytovat vysokou dostupnost (HA)?!

Bohužel plánovač Kubernetes z vlastní iniciativy nesplňuje pravidla samostatné existence (anti-afinitní) pro lusky. Musí být výslovně uvedeno:

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

To je vše. Nyní budou moduly naplánovány na různé uzly (tato podmínka se kontroluje pouze během plánování, ale ne během jejich provozu - proto requiredDuringSchedulingIgnoredDuringExecution).

Tady mluvíme o podAntiAffinity na různých uzlech: topologyKey: "kubernetes.io/hostname", - a ne o různých zónách dostupnosti. Abyste zavedli plnohodnotnou HA, budete se muset v tomto tématu ponořit hlouběji.

7. Ignorování PodDisruptionBudgets

Představte si, že máte produkční zatížení clusteru Kubernetes. Pravidelně musí být uzly a samotný cluster aktualizovány (nebo vyřazeny z provozu). PodDisruptionBudget (PDB) je něco jako smlouva o záruce služeb mezi správci clusteru a uživateli.

PDB vám umožňuje vyhnout se přerušením služeb způsobeným nedostatkem uzlů:

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

V tomto příkladu jako uživatel clusteru řeknete administrátorům: „Hej, mám službu ošetřovatele v zoo a ať děláte cokoli, rád bych měl vždy k dispozici alespoň 2 repliky této služby.“

Můžete si o tom přečíst více zde.

8. Více uživatelů nebo prostředí ve společném klastru

Jmenné prostory Kubernetes (jmenné prostory) neposkytují silnou izolaci.

Obvyklá mylná představa je, že pokud nasadíte neprodukční zatížení do jednoho jmenného prostoru a prodové zatížení do jiného, se navzájem nijak neovlivní... Určité úrovně izolace však lze dosáhnout pomocí požadavků/omezení zdrojů, nastavení kvót a nastavení prioritních tříd. Určitou „fyzickou“ izolaci v datové rovině poskytují afinity, tolerance, skvrny (nebo selektory uzlů), ale takové oddělení je docela obtížné nářadí.

Ti, kteří potřebují kombinovat oba typy zátěže ve stejném clusteru, se budou muset vypořádat se složitostí. Pokud taková potřeba není a můžete si ji dovolit ještě jeden shluk (řekněme ve veřejném cloudu), pak je lepší to udělat. Tím dosáhnete mnohem vyšší úrovně izolace.

9. ExternalTrafficPolicy: Cluster

Velmi často pozorujeme, že veškerý provoz uvnitř clusteru přichází přes službu jako NodePort, pro kterou je nastavena výchozí politika externalTrafficPolicy: Cluster... Znamená to, že Port uzlu je otevřený na každém uzlu v clusteru a kterýkoli z nich můžete použít k interakci s požadovanou službou (sadou modulů).

10 běžných chyb při používání Kubernetes

Reálné pody spojené s výše zmíněnou službou NodePort jsou přitom obvykle dostupné pouze na určitém podmnožina těchto uzlů. Jinými slovy, pokud se připojím k uzlu, který nemá požadovaný modul, přesměruje provoz na jiný uzel, přidání chmele a zvýšení latence (pokud jsou uzly umístěny v různých zónách dostupnosti/datových centrech, může být latence poměrně vysoká; navíc se zvýší náklady na odchozí provoz).

Na druhou stranu, pokud má určitá služba Kubernetes nastavenou politiku externalTrafficPolicy: Local, pak se NodePort otevře pouze na těch uzlech, kde skutečně běží požadované moduly. Při použití externího load balanceru, který kontroluje stav (zdravotní kontrola) koncové body (jak to dělá AWS ELB), On bude posílat provoz pouze do nezbytných uzlů, což bude mít příznivý vliv na zpoždění, výpočetní potřeby, výstupní účty (a zdravý rozum diktuje totéž).

Je velká šance, že už něco takového používáte traefik nebo nginx-ingress-controller jako koncový bod NodePort (nebo LoadBalancer, který také používá NodePort) ke směrování příchozího provozu HTTP a nastavení této možnosti může výrazně snížit latenci takových požadavků.

В této publikace Můžete se dozvědět více o externalTrafficPolicy, jejích výhodách a nevýhodách.

10. Nenechte se připoutat ke shlukům a nezneužívejte řídicí rovinu

Dříve bylo obvyklé volat servery správnými jmény: Anton, HAL9000 a Colossus... Dnes je nahradily náhodně generované identifikátory. Zvyk však zůstal a nyní vlastní jména jdou do shluků.

Typický příběh (založený na skutečných událostech): vše začalo proof of concept, takže cluster měl hrdé jméno Testování… Uplynuly roky a STÁLE se používá ve výrobě a každý se na něj bojí sáhnout.

Na tom, jak se shluky mění v mazlíčky, není nic zábavného, ​​takže je během cvičení doporučujeme pravidelně odstraňovat zotavení po havárii (to pomůže chaosové inženýrství - Cca. překlad.). Kromě toho by nebylo na škodu zapracovat na ovládací vrstvě (řídicí rovina). Bát se ho dotknout není dobré znamení. Atd. mrtví? Kluci, vy jste opravdu v průšvihu!

Na druhou stranu byste se neměli nechat unést manipulací. S časem řídicí vrstva se může zpomalit. S největší pravděpodobností je to způsobeno velkým množstvím objektů vytvářených bez jejich rotace (běžná situace při použití Helmu s výchozím nastavením, proto se jeho stav v configmaps/secrets neaktualizuje - v důsledku toho se tisíce objektů hromadí v řídicí vrstva) nebo s neustálou úpravou objektů kube-api (pro automatické škálování, pro CI/CD, pro monitorování, protokoly událostí, řadiče atd.).

Kromě toho doporučujeme zkontrolovat smlouvy SLA/SLO se spravovaným poskytovatelem Kubernetes a věnovat pozornost zárukám. Prodejce může zaručit kontrola dostupnosti vrstvy (nebo jeho podkomponenty), ale ne zpoždění požadavků p99, které mu odešlete. Jinými slovy, můžete vstoupit kubectl get nodesa obdržíte odpověď až po 10 minutách, což nebude porušení podmínek smlouvy o poskytování služeb.

11. Bonus: použití nejnovější značky

Ale to už je klasika. V poslední době se s touto technikou setkáváme méně často, protože mnozí, poučeni z hořkých zkušeností, přestali značku používat :latest a začal připínat verze. Hurá!

ECR zachovává neměnnost značek obrázků; Doporučujeme, abyste se s touto pozoruhodnou funkcí seznámili.

Shrnutí

Nečekejte, že vše bude fungovat přes noc: Kubernetes není všelék. Špatná aplikace zůstane tímto způsobem i v Kubernetes (a asi bude hůř). Neopatrnost povede k nadměrné složitosti, pomalé a stresující práci kontrolní vrstvy. Navíc riskujete, že zůstanete bez strategie obnovy po havárii. Neočekávejte, že Kubernetes poskytne izolaci a vysokou dostupnost hned po vybalení. Věnujte nějaký čas tomu, aby vaše aplikace byla skutečně cloudová nativní.

Můžete se seznámit s neúspěšnými zkušenostmi různých týmů v tuto sbírku povídek od Henninga Jacobse.

Ti, kteří chtějí přidat do seznamu chyb uvedených v tomto článku, nás mohou kontaktovat na Twitteru (@MarekBartík, @MstrsObserver).

PS od překladatele

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář