Devět Kubernetes výkonových tipů

Devět Kubernetes výkonových tipů

Ahoj všichni! Jmenuji se Oleg Sidorenkov a pracuji ve společnosti DomClick jako vedoucí týmu infrastruktury. Kostku používáme k prodeji již více než tři roky a za tuto dobu jsme s ní zažili mnoho různých zajímavých okamžiků. Dnes vám řeknu, jak můžete správným přístupem vymáčknout ještě více výkonu z vanilla Kubernetes pro váš cluster. Připravit pozor teď!

Všichni dobře víte, že Kubernetes je škálovatelný open source systém pro orchestraci kontejnerů; no, nebo 5 binárních souborů, které dělají kouzla řízením životního cyklu vašich mikroslužeb v prostředí serveru. Navíc se jedná o poměrně flexibilní nástroj, který lze sestavit jako konstruktér Lego pro maximální přizpůsobení pro různé úkoly.

A vše se zdá být v pořádku: házejte servery do clusteru, jako dříví do topeniště, a neznáte smutek. Ale pokud jste pro životní prostředí, pak si pomyslíte: "Jak mohu udržet oheň v kamnech a litovat lesa?". Jinými slovy, jak najít způsoby, jak zlepšit infrastrukturu a snížit náklady.

1. Sledujte zdroje týmu a aplikací

Devět Kubernetes výkonových tipů

Jednou z nejbanálnějších, ale nejúčinnějších metod je zavedení požadavků/limitů. Oddělte aplikace podle jmenných prostorů a jmenné prostory podle vývojových týmů. Nastavte aplikaci před nasazením hodnot spotřeby času procesoru, paměti, dočasných úložišť.

resources:
   requests:
     memory: 2Gi
     cpu: 250m
   limits:
     memory: 4Gi
     cpu: 500m

Zkušeností jsme došli k závěru: nemá cenu navyšovat požadavky z limitů více než dvakrát. Velikost clusteru se vypočítává na základě požadavků, a pokud aplikaci nastavíte na rozdíl ve zdrojích, například 5-10krát, pak si představte, co se stane s vaším uzlem, když se zaplní pody a náhle přijme zátěž. Nic dobrého. Minimálně škrcení a maximálně se rozlučte s pracovníkem a cyklicky zatěžujte zbytek uzlů poté, co se pody začnou pohybovat.

Navíc s pomocí limitranges můžete nastavit hodnoty zdrojů pro kontejner na začátku - minimální, maximální a výchozí:

➜  ~ kubectl describe limitranges --namespace ops
Name:       limit-range
Namespace:  ops
Type        Resource           Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----        --------           ---   ---   ---------------  -------------  -----------------------
Container   cpu                50m   10    100m             100m           2
Container   ephemeral-storage  12Mi  8Gi   128Mi            4Gi            -
Container   memory             64Mi  40Gi  128Mi            128Mi          2

Nezapomeňte omezit prostředky jmenného prostoru, aby jeden příkaz nemohl zabrat všechny prostředky klastru:

➜  ~ kubectl describe resourcequotas --namespace ops
Name:                   resource-quota
Namespace:              ops
Resource                Used          Hard
--------                ----          ----
limits.cpu              77250m        80
limits.memory           124814367488  150Gi
pods                    31            45
requests.cpu            53850m        80
requests.memory         75613234944   150Gi
services                26            50
services.loadbalancers  0             0
services.nodeports      0             0

Jak můžete vidět z popisu resourcequotas, pokud chce příkaz ops nasadit moduly, které spotřebují dalších 10 cpu, pak to plánovač neumožní a vydá chybu:

Error creating: pods "nginx-proxy-9967d8d78-nh4fs" is forbidden: exceeded quota: resource-quota, requested: limits.cpu=5,requests.cpu=5, used: limits.cpu=77250m,requests.cpu=53850m, limited: limits.cpu=10,requests.cpu=10

Chcete-li vyřešit podobný problém, můžete napsat nástroj, například jako tento, který může uložit a potvrdit stav prostředků příkazu.

2. Vyberte nejlepší úložiště souborů

Devět Kubernetes výkonových tipů

Zde bych se rád dotkl tématu persistentních svazků a diskového subsystému pracovních uzlů Kubernetes. Doufám, že tu "Kostku" na HDD nikdo nepoužívá ve výrobě, ale někdy už nestačí ani obyčejné SSD. Čelili jsme takovému problému, že protokoly zabíjely disk I/O operacemi a zde není příliš mnoho řešení:

  • Použijte vysoce výkonné SSD nebo přejděte na NVMe (pokud spravujete svůj vlastní hardware).

  • Snižte úroveň protokolování.

  • Proveďte "chytré" vyvážení lusků, které znásilňují disk (podAntiAffinity).

Snímek obrazovky výše ukazuje, co se stane pod nginx-ingress-controller s diskem, když je povoleno protokolování access_logs (~12k protokolů/s). Takový stav samozřejmě může vést k degradaci všech aplikací na tomto uzlu.

Co se týče PV, bohužel, nezkoušel jsem všechno. druhů Trvalé svazky. Použijte nejlepší možnost, která vám vyhovuje. Historicky se u nás stávalo, že malá část služeb potřebuje svazky RWX a už dávno pro tento úkol začali využívat úložiště NFS. Levné a dostačující. Jasně, že jsme s ním jedli kraviny - buďte zdraví, ale naučili jsme se, jak ho vyladit, a už ho hlava nebolí. A pokud je to možné, přejděte na úložiště objektů S3.

3. Vytvářejte optimalizované obrázky

Devět Kubernetes výkonových tipů

Nejlepší je používat obrázky optimalizované pro kontejnery, aby je Kubernetes mohl načítat rychleji a spouštět je efektivněji. 

Optimalizace znamená, že obrázky:

  • obsahovat pouze jednu aplikaci nebo vykonávat pouze jednu funkci;

  • malá velikost, protože velké obrázky se po síti přenášejí hůře;

  • mít koncové body zdraví a připravenosti, které může Kubernetes použít k akci v případě výpadku;

  • používat operační systémy přátelské ke kontejnerům (jako Alpine nebo CoreOS), které jsou odolnější vůči chybám konfigurace;

  • používejte vícestupňová sestavení, abyste mohli nasadit pouze zkompilované aplikace a nikoli doprovodné zdroje.

Existuje mnoho nástrojů a služeb, které vám umožňují kontrolovat a optimalizovat snímky za chodu. Je důležité, aby byly vždy aktuální a bezpečné. V důsledku toho získáte:

  1. Snížené zatížení sítě v celém clusteru.

  2. Zkrácená doba spuštění kontejneru.

  3. Menší velikost celého vašeho registru Docker.

4. Použijte mezipaměť DNS

Devět Kubernetes výkonových tipů

Pokud mluvíme o vysokém zatížení, pak bez vyladění systému DNS clusteru je život docela mizerný. Kdysi dávno vývojáři Kubernetes podporovali své řešení kube-dns. Byl implementován i u nás, ale tento software nijak zvlášť neladil a nepodával požadovaný výkon, i když, jak se zdá, úkol je jednoduchý. Pak se objevily coredny, na které jsme přešli a neznali smutek, později se to stalo výchozí DNS službou v K8s. V určitém okamžiku jsme vyrostli až na 40 tisíc rps systému DNS a toto řešení také nestačilo. Ale šťastnou náhodou se objevil Nodelocaldns, známý jako místní mezipaměť uzlu, aka NodeLocal DNSCache.

Proč to používáme? V linuxovém jádře je chyba, která při vícenásobném přístupu přes conntrack NAT přes UDP vede k race condition pro zápis do conntrack tabulek a část provozu přes NAT je ztracena (každá cesta přes Službu je NAT). Nodelocaldns řeší tento problém tím, že se zbaví NAT a upgraduje konektivitu TCP na upstream DNS, stejně jako lokálně ukládá upstream DNS dotazy (včetně krátké 5sekundové záporné mezipaměti).

5. Automaticky upravte měřítko vodorovně a svisle

Devět Kubernetes výkonových tipů

Můžete s jistotou říci, že všechny vaše mikroslužby jsou připraveny na dvou až trojnásobné zvýšení zátěže? Jak správně alokovat zdroje vašim aplikacím? Udržování několika modulů spuštěných nad pracovní zátěž může být nadbytečné a jejich udržování zády k sobě riskuje prostoje v důsledku náhlého nárůstu provozu služby. Zlatá střední cesta pomáhá dosáhnout násobícího kouzla takové služby jako Autoscaler horizontální pod и Vertikální stojan Autoscaler.

VPA umožňuje automaticky zvyšovat požadavky/limity vašich kontejnerů v podu na základě skutečného využití. Jak to může být užitečné? Pokud máte moduly, které z nějakého důvodu nelze horizontálně zmenšit (což není zcela spolehlivé), můžete zkusit důvěřovat VPA, že změní své zdroje. Jeho funkcí je systém doporučení založený na historických a aktuálních datech z metrického serveru, takže pokud nechcete automaticky měnit požadavky/limity, můžete jednoduše sledovat doporučené zdroje pro vaše kontejnery a optimalizovat nastavení pro úsporu CPU a paměti. v klastru.

Devět Kubernetes výkonových tipůObrázek převzat z https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Plánovač v Kubernetes je vždy založen na požadavcích. Ať tam zadáte jakoukoli hodnotu, plánovač na základě ní vyhledá vhodný uzel. Hodnotu limitu potřebuje kublet, aby věděl, kdy přiškrtit nebo zabít lusk. A protože jediným důležitým parametrem je hodnota requestů, VPA s tím bude pracovat. Kdykoli vertikálně škálujete aplikaci, definujete, jaké požadavky by měly být. A co se potom stane s limity? Tento parametr bude také proporcionálně škálován.

Zde jsou například typická nastavení pod:

resources:
   requests:
     memory: 250Mi
     cpu: 200m
   limits:
     memory: 500Mi
     cpu: 350m

Modul doporučení určí, že vaše aplikace potřebuje 300 m CPU a 500 Mi, aby správně fungovala. Získáte tato nastavení:

resources:
   requests:
     memory: 500Mi
     cpu: 300m
   limits:
     memory: 1000Mi
     cpu: 525m

Jak je uvedeno výše, jedná se o proporcionální škálování založené na poměru požadavků/limitů v manifestu:

  • CPU: 200m → 300m: poměr 1:1.75;

  • Paměť: 250Mi → 500Mi: poměr 1:2.

s ohledem na HPA, pak je mechanismus fungování transparentnější. Prahové hodnoty jsou nastaveny pro metriky, jako je procesor a paměť, a pokud průměr všech replik překročí práh, pak se aplikace změní o +1 pod, dokud hodnota neklesne pod práh, nebo dokud není dosaženo maximálního počtu replik.

Devět Kubernetes výkonových tipůObrázek převzat z https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

Kromě obvyklých metrik, jako je CPU a paměť, můžete nastavit prahové hodnoty pro své vlastní metriky Prometheus a pracovat s nimi, pokud se domníváte, že je to nejpřesnější způsob, jak určit, kdy škálovat vaši aplikaci. Jakmile se aplikace stabilizuje pod zadaným prahem metriky, HPA začne zmenšovat pody na minimální počet replik nebo dokud zatížení nedosáhne zadaného prahu.

6. Nezapomeňte na Node Affinity a Pod Affinity

Devět Kubernetes výkonových tipů

Ne všechny uzly běží na stejném hardwaru a ne všechny moduly musí spouštět výpočetně náročné aplikace. Kubernetes umožňuje určit specializaci pomocí uzlů a podů Afinita uzlu и Pod Affinity.

Pokud máte uzly vhodné pro výpočetně náročné operace, pak pro maximální efektivitu je lepší svázat aplikace s příslušnými uzly. Chcete-li to provést, použijte nodeSelector se štítkem uzlu.

Řekněme, že máte dva uzly: jeden s CPUType=HIGHFREQ a velký počet rychlých jader, další s MemoryType=HIGHMEMORY více paměti a rychlejší výkon. Nejjednodušší způsob je přiřadit nasazení pod uzlu HIGHFREQpřidáním do sekce spec takový selektor:

…
nodeSelector:
	CPUType: HIGHFREQ

Nákladnějším a konkrétnějším způsobem, jak toho dosáhnout, je použití nodeAffinity v oboru affinity část spec. Jsou dvě možnosti:

  • requiredDuringSchedulingIgnoredDuringExecution: tvrdé nastavení (plánovač nasadí moduly pouze na konkrétní uzly (a nikde jinde));

  • preferredDuringSchedulingIgnoredDuringExecution: měkké nastavení (plánovač se pokusí nasadit na konkrétní uzly, a pokud selže, pokusí se nasadit na další dostupný uzel).

Můžete zadat konkrétní syntaxi pro správu štítků uzlů, například In, NotIn, Exists, DoesNotExist, Gt nebo Lt. Pamatujte však, že složité metody v dlouhých seznamech štítků zpomalí rozhodování v kritických situacích. Jinými slovy, nekomplikujte to.

Jak již bylo zmíněno výše, Kubernetes umožňuje nastavit vazbu aktuálních podů. To znamená, že můžete zajistit, aby určité moduly spolupracovaly s jinými moduly ve stejné zóně dostupnosti (relevantní pro cloudy) nebo uzlech.

В podAffinity okraje affinity část spec jsou k dispozici stejná pole jako v případě nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution и preferredDuringSchedulingIgnoredDuringExecution. Jediný rozdíl je v tom matchExpressions připojí pody k uzlu, který již provozuje pod s tímto štítkem.

Více Kubernetes nabízí pole podAntiAffinity, který na rozdíl od toho neváže lusk na uzel se specifickými lusky.

O výrazech nodeAffinity lze dát stejnou radu: snažte se udržovat pravidla jednoduchá a logická, nesnažte se zahltit specifikaci podu složitým souborem pravidel. Je velmi snadné vytvořit pravidlo, které neodpovídá podmínkám clusteru, což zvyšuje zátěž plánovače a snižuje celkový výkon.

7. Skvrny a tolerance

Existuje další způsob, jak spravovat plánovač. Pokud máte velký cluster se stovkami uzlů a tisíci mikroslužeb, je velmi obtížné zabránit tomu, aby určité pody byly hostovány určitými uzly.

K tomu pomáhá mechanismus poskvrnění – zakazující pravidla. Můžete například zabránit určitým uzlům ve spouštění modulů v určitých scénářích. Chcete-li použít poskvrnu na konkrétní uzel, použijte volbu taint v kubectl. Specifikujte klíč a hodnotu a poté nakažte jako NoSchedule nebo NoExecute:

$ kubectl taint nodes node10 node-role.kubernetes.io/ingress=true:NoSchedule

Za zmínku také stojí, že mechanismus znečištění podporuje tři hlavní efekty: NoSchedule, NoExecute и PreferNoSchedule.

  • NoSchedule znamená, že dokud nebude odpovídající záznam ve specifikaci modulu tolerations, nelze jej nasadit do uzlu (v tomto příkladu node10).

  • PreferNoSchedule - zjednodušená verze NoSchedule. V tomto případě se plánovač pokusí nepřidělit pody, které nemají odpovídající záznam. tolerations na uzel, ale nejedná se o pevný limit. Pokud v clusteru nejsou žádné prostředky, začnou se na tomto uzlu nasazovat moduly.

  • NoExecute - tento efekt spustí okamžitou evakuaci lusků, které nemají odpovídající vstup tolerations.

Je zvláštní, že toto chování lze vrátit zpět pomocí tolerančního mechanismu. To je výhodné, když existuje „zakázaný“ uzel a potřebujete na něj umístit pouze infrastrukturní služby. Jak to udělat? Povolte pouze ty lusky, pro které existuje vhodná tolerance.

Takto by vypadala specifikace pod:

spec:
   tolerations:
     - key: "node-role.kubernetes.io/ingress"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"

To neznamená, že při příštím přemístění modul zasáhne přesně tento uzel, nejedná se o mechanismus Afinity uzlu a nodeSelector. Ale kombinací několika funkcí můžete dosáhnout velmi flexibilního nastavení plánovače.

8. Nastavte prioritu nasazení podu

To, že jste nakonfigurovali vazby pod-to-node, neznamená, že se všemi pody by se mělo zacházet se stejnou prioritou. Můžete například chtít nasadit některé moduly před ostatními.

Kubernetes nabízí různé způsoby, jak nastavit prioritu podu a preempci. Nastavení se skládá z několika částí: objekt PriorityClass a popisy polí priorityClassName ve specifikaci podu. Zvažte příklad:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 99999
globalDefault: false
description: "This priority class should be used for very important pods only"

tvoříme PriorityClass, zadejte název, popis a hodnotu. Ten vyšší value, tím vyšší priorita. Hodnota může být libovolné 32bitové celé číslo menší nebo rovné 1 000 000 000. Vyšší hodnoty jsou vyhrazeny pro kritické systémové moduly, které obvykle nelze preemptovat. K vystěhování dojde pouze v případě, že modul s vysokou prioritou se nemá kam otočit, pak budou některé moduly z konkrétního uzlu evakuovány. Pokud je pro vás tento mechanismus příliš tuhý, můžete přidat možnost preemptionPolicy: Never, a pak nedojde k žádné preempci, pod bude první ve frontě a počká, až pro něj plánovač najde volné zdroje.

Dále vytvoříme lusk, ve kterém určíme název priorityClassName:

apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    role: myrole
 spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
  priorityClassName: high-priority
          

Můžete vytvořit tolik prioritních tříd, kolik chcete, i když se doporučuje nenechat se tím unést (řekněme, omezit se na nízkou, střední a vysokou prioritu).

V případě potřeby tak můžete zvýšit efektivitu nasazení kritických služeb, jako je nginx-ingress-controller, coredns atd.

9. Optimalizujte svůj ETCD cluster

Devět Kubernetes výkonových tipů

ETCD lze nazvat mozkem celého shluku. Je velmi důležité udržovat provoz této databáze na vysoké úrovni, protože na tom závisí rychlost operací v "Cube". Poměrně standardním a zároveň dobrým řešením by bylo ponechat ETCD cluster na hlavních uzlech, aby bylo minimální zpoždění na kube-apiserver. Pokud to není možné, umístěte ETCD co nejblíže, s dobrou šířkou pásma mezi účastníky. Věnujte také pozornost tomu, kolik uzlů z ETCD může vypadnout bez poškození clusteru.

Devět Kubernetes výkonových tipů

Mějte na paměti, že nadměrné zvýšení počtu účastníků v clusteru může zvýšit odolnost proti chybám na úkor výkonu, všeho by mělo být s mírou.

Pokud mluvíme o nastavení služby, existuje několik doporučení:

  1. Mít dobrý hardware na základě velikosti clusteru (můžete si přečíst zde).

  2. Vylaďte několik parametrů, pokud jste klastr rozprostřeli mezi pár DC nebo vaši síť a disky ponechají hodně na přání (můžete si přečíst zde).

Závěr

Tento článek popisuje body, které se náš tým snaží dodržovat. Toto není podrobný popis akcí, ale možnosti, které mohou být užitečné pro optimalizaci režie clusteru. Je jasné, že každý cluster je svým způsobem jedinečný a řešení ladění se mohou značně lišit, takže by bylo zajímavé od vás získat zpětnou vazbu: jak svůj cluster Kubernetes monitorujete, jak zlepšujete jeho výkon. Podělte se o své zkušenosti v komentářích, bude zajímavé to vědět.

Zdroj: www.habr.com