Kubernetes: prečo je dôležité nastaviť riadenie zdrojov systému?

Zvyčajne vzniká potreba zabezpečiť vyhradenú skupinu zdrojov pre aplikáciu na jej správnu a stabilnú činnosť. Ale čo ak na tých istých prostriedkoch pracuje niekoľko aplikácií súčasne? Ako zabezpečiť minimálne potrebné zdroje pre každú z nich? Akým spôsobom je možné obmedziť spotrebu zdrojov? Ako správne rozdeliť záťaž medzi uzlami? Ako zabezpečiť fungovanie mechanizmu horizontálneho škálovania v prípade rastu zaťaženia aplikácií?

Kubernetes: prečo je dôležité nastaviť riadenie zdrojov systému?

Treba začať tým, aké hlavné typy zdrojov existujú v systéme — samozrejme, ide o procesorový čas a operačnú pamäť. V manifestoch k8s sa tieto typy zdrojov merajú v nasledujúcich jednotkách:

  • CPU — v jadrach
  • RAM — v bajtoch

Pre každý zdroj je pritom možné nastaviť dva typy požiadaviek — requests a limits. Requests popisuje minimálne požiadavky na voľné zdroje uzla pre spustenie kontajnera (a podu ako celku), zatiaľ čo limits stanovuje prísne obmedzenie zdrojov dostupných pre kontajner.

Je dôležité pochopiť, že v manifeste nie je nevyhnutné výslovne definovať oba typy, pričom správanie bude nasledujúce:

  • Ak je výslovne zadané iba limits zdroja, requests pre tento zdroj automaticky nadobúda hodnotu rovnu limits (v tom sa môžete presvedčiť vyvolaním describe entity). T.j. vlastne práca kontajnera bude obmedzená na rovnaké množstvo zdrojov, ktoré potrebuje pre svoj štart.
  • Ak je pre zdroj výslovne zadané len requests, žiadne obmedzenia pre tento zdroj nie sú nastavené — t.j. kontajner je obmedzený iba zdrojmi samotného uzla.

Existuje tiež možnosť nastaviť správu zdrojov nielen na úrovni konkrétneho kontajnera, ale aj na úrovni namespace pomocou nasledujúcich entít:

  • LimitRange — popisuje politiku obmedzenia na úrovni kontajnera/podu v ns a je potrebná na to, aby sa opísali predvolené obmedzenia na kontajner/pod, ako aj na zabránenie vytváraniu zjavne prekročených kontajnerov/podov (alebo naopak), obmedzovať ich počet a určiť možný rozdiel hodnôt v limits a requests.
  • ResourceQuotas — opisujú politiku obmedzenia vo všeobecnosti pre všetky kontajnery v ns a zvyčajne sa používa na rozdelenie zdrojov medzi prostrediami (užitočné, keď nie sú prostredia prísne rozdelené na úrovni uzlov)

Nižšie sú uvedené príklady manifestov, kde sú nastavené obmedzenia na zdroje:

  • Na úrovni konkrétneho kontajnera:

    containers:
    - name: app-nginx
      image: nginx
      resources:
        requests:
          memory: 1Gi
        limits:
          cpu: 200m

    T.j. v tomto prípade na spustenie kontajnera s nginx bude potrebné mať aspoň 1G voľnej RAM a 0.2 CPU na uzle, pritom maximálne kontajner môže získať 0.2 CPU a celú dostupnú RAM na uzle.

  • Na úrovni celého ns:

    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: nxs-test
    spec:
      hard:
        requests.cpu: 300m
        requests.memory: 1Gi
        limits.cpu: 700m
        limits.memory: 2Gi

    T.j. súčet všetkých request kontajnerov v predvolenom ns nemôže prekročiť 300m pre CPU a 1G pre RAM, zatiaľ čo súčet všetkých limitov — 700m pre CPU a 2G pre RAM.

  • Predvolené obmedzenia pre kontajnery v ns:

    apiVersion: v1
    kind: LimitRange
    metadata:
      name: nxs-limit-per-container
    spec:
     limits:
       - type: Container
         defaultRequest:
           cpu: 100m
           memory: 1Gi
         default:
           cpu: 1
           memory: 2Gi
         min:
           cpu: 50m
           memory: 500Mi
         max:
           cpu: 2
           memory: 4Gi

    T.j. v predvolenom namespace pre všetky kontajnery bude predvolene nastavený request na 100m pre CPU a 1G pre RAM, limit — 1 CPU a 2G. Zároveň je nastavené aj obmedzenie pre možné hodnoty v request/limit pre CPU (50m < x < 2) a RAM (500M < x < 4G).

  • Obmedzenia na úrovni podov ns:

    apiVersion: v1
    kind: LimitRange
    metadata:
     name: nxs-limit-pod
    spec:
     limits:
     - type: Pod
       max:
         cpu: 4
         memory: 1Gi

    T.j. pre každý pod v predvolenom ns bude nastavené obmedzenie na 4 vCPU a 1G.

Teraz by som chcel povedať, aké výhody nám môže priniesť nastavenie týchto obmedzení.

Mechanizmus vyvažovania zaťaženia medzi uzlami

Ako je známe, za rozdeľovanie podov medzi uzlami zodpovedá taký komponent k8s, ako scheduler, ktorý pracuje na základe určitého algoritmu. Tento algoritmus pri vyberaní optimálneho uzla na spustenie prechádza dvoma fázami:

  1. Filtrácia
  2. Rangovanie

T.j. v súlade s opísanou politikou sa najprv vyberajú uzly, na ktorých je možné spustiť pod na základe súboru predicates (vrátane kontroly, či má uzol dostatok zdrojov na spustenie podu — PodFitsResources), a potom pre každý z týchto uzlov, podľa priorities body získavajú body (a to vrátane toho, že čím viac voľných zdrojov má uzol, tým viac bodov mu je pridelených — LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) a pod sa spúšťa na uzle s najvyšším počtom bodov (ak tomuto kritériu vyhovuje viacero uzlov, vyberie sa náhodný z nich).

Pri tom je potrebné si uvedomiť, že scheduler pri hodnotení dostupných zdrojov uzla sa riadi údajmi, ktoré sú uložené v etcd — t.j. súčtom requested/limit zdroja každého podu, ktorý je spustený na tomto uzle, ale nie skutočnou spotrebou zdrojov. Túto informáciu je možné získať z výstupu príkazu kubectl describe node $NODE, napríklad:

# kubectl describe nodes nxs-k8s-s1
..
Non-terminated Pods:         (9 in total)
  Namespace                  Name                                         CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
  ---------                  ----                                         ------------  ----------  ---------------  -------------  ---
  ingress-nginx              nginx-ingress-controller-754b85bf44-qkt2t    0 (0%)        0 (0%)      0 (0%)           0 (0%)         233d
  kube-system                kube-flannel-26bl4                           150m (0%)     300m (1%)   64M (0%)         500M (1%)      233d
  kube-system                kube-proxy-exporter-cb629                    0 (0%)        0 (0%)      0 (0%)           0 (0%)         233d
  kube-system                kube-proxy-x9fsc                             0 (0%)        0 (0%)      0 (0%)           0 (0%)         233d
  kube-system                nginx-proxy-k8s-worker-s1                    25m (0%)      300m (1%)   32M (0%)         512M (1%)      233d
  nxs-monitoring             alertmanager-main-1                          100m (0%)     100m (0%)   425Mi (1%)       25Mi (0%)      233d
  nxs-logging                filebeat-lmsmp                               100m (0%)     0 (0%)      100Mi (0%)       200Mi (0%)     233d
  nxs-monitoring             node-exporter-v4gdq                          112m (0%)     122m (0%)   200Mi (0%)       220Mi (0%)     233d
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests           Limits
  --------           --------           ------
  cpu                487m (3%)          822m (5%)
  memory             15856217600 (2%)  749976320 (3%)
  ephemeral-storage  0 (0%)             0 (0%)

Tu vidíme všetky podi spustené na konkrétnom uzle, ako aj zdroje, ktoré požaduje každý z podov. A takto vyzerajú záznamy scheduler pri spustení podu cronjob-cron-events-1573793820-xt6q9 (táto informácia v zázname scheduler sa objaví pri nastavení úrovne logovania na 10 v argumentoch príkazu spustenia —v=10):

záznam

I1115 07:57:21.637791       1 scheduling_queue.go:908] Chystá sa naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                           
I1115 07:57:21.637804       1 scheduler.go:453] Pokus o naplánovanie podu: nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                                    
I1115 07:57:21.638285       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s5 je povolené, uzol beží iba s 16 zo 110 podov.                                                                               
I1115 07:57:21.638300       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s6 je povolené, uzol beží iba s 20 zo 110 podov.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s3 je povolené, uzol beží iba s 20 zo 110 podov.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s4 je povolené, uzol beží iba s 17 zo 110 podov.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s10 je povolené, uzol beží iba s 16 zo 110 podov.                                                                              
I1115 07:57:21.638365       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s12 je povolené, uzol beží iba s 9 zo 110 podov.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s11 je povolené, uzol beží iba s 11 zo 110 podov.                                                                              
I1115 07:57:21.638385       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s1 je povolené, uzol beží iba s 19 zo 110 podov.                                                                               
I1115 07:57:21.638402       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s2 je povolené, uzol beží iba s 21 zo 110 podov.                                                                               
I1115 07:57:21.638383       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s9 je povolené, uzol beží iba s 16 zo 110 podov.                                                                               
I1115 07:57:21.638335       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s8 je povolené, uzol beží iba s 18 zo 110 podov.                                                                               
I1115 07:57:21.638408       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s13 je povolené, uzol beží iba s 8 zo 110 podov.                                                                               
I1115 07:57:21.638478       1 predicates.go:1369] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s10 je povolené, existujúce podmínky anti-affinity sú splnené.                                                                         
I1115 07:57:21.638505       1 predicates.go:1369] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s8 je povolené, existujúce podmínky anti-affinity sú splnené.                                                                          
I1115 07:57:21.638577       1 predicates.go:1369] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s9 je povolené, existujúce podmínky anti-affinity sú splnené.                                                                          
I1115 07:57:21.638583       1 predicates.go:829] Naplánovať pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 na uzle nxs-k8s-s7 je povolené, uzol beží iba s 25 zo 110 podov.                                                                               
I1115 07:57:21.638932       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, kapacita 39900 milikórov 66620178432 bajtov pamäte, celkový požiadavok 2343 milikórov 9640186880 bajtov pamäte, skóre 9        
I1115 07:57:21.638946       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, kapacita 39900 milikórov 66620178432 bajtov pamäte, celkový požiadavok 2343 milikórov 9640186880 bajtov pamäte, skóre 8           
I1115 07:57:21.638961       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, kapacita 39900 milikórov 66620170240 bajtov pamäte, celkový požiadavok 4107 milikórov 11307422720 bajtov pamäte, skóre 9        
I1115 07:57:21.638971       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, kapacita 39900 milikórov 66620178432 bajtov pamäte, celkový požiadavok 5847 milikórov 24333637120 bajtov pamäte, skóre 7        
I1115 07:57:21.638975       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, kapacita 39900 milikórov 66620170240 bajtov pamäte, celkový požiadavok 4107 milikórov 11307422720 bajtov pamäte, skóre 8           
I1115 07:57:21.638990       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, kapacita 39900 milikórov 66620178432 bajtov pamäte, celkový požiadavok 5847 milikórov 24333637120 bajtov pamäte, skóre 7           
I1115 07:57:21.639022       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s10: TaintTolerationPriority, skóre: (10)                                                                                                        
I1115 07:57:21.639030       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s8: TaintTolerationPriority, skóre: (10)                                                                                                         
I1115 07:57:21.639034       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s9: TaintTolerationPriority, skóre: (10)                                                                                                         
I1115 07:57:21.639041       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s10: NodeAffinityPriority, skóre: (0)                                                                                                            
I1115 07:57:21.639053       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s8: NodeAffinityPriority, skóre: (0)                                                                                                             
I1115 07:57:21.639059       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s9: NodeAffinityPriority, skóre: (0)                                                                                                             
I1115 07:57:21.639061       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s10: InterPodAffinityPriority, skóre: (0)                                                                                                                   
I1115 07:57:21.639063       1 selector_spreading.go:146] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, skóre: (10)                                                                                                                   
I1115 07:57:21.639073       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s8: InterPodAffinityPriority, skóre: (0)                                                                                                                    
I1115 07:57:21.639077       1 selector_spreading.go:146] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, skóre: (10)                                                                                                                    
I1115 07:57:21.639085       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s9: InterPodAffinityPriority, skóre: (0)                                                                                                                    
I1115 07:57:21.639088       1 selector_spreading.go:146] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, skóre: (10)                                                                                                                    
I1115 07:57:21.639103       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, skóre: (10)                                                                                                         
I1115 07:57:21.639109       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, skóre: (10)                                                                                                          
I1115 07:57:21.639114       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, skóre: (10)                                                                                                          
I1115 07:57:21.639127       1 generic_scheduler.go:781] Host nxs-k8s-s10 => skóre 100037                                                                                                                                                                            
I1115 07:57:21.639150       1 generic_scheduler.go:781] Host nxs-k8s-s8 => skóre 100034                                                                                                                                                                             
I1115 07:57:21.639154       1 generic_scheduler.go:781] Host nxs-k8s-s9 => skóre 100037                                                                                                                                                                             
I1115 07:57:21.639267       1 scheduler_binder.go:269] AssumePodVolumes pre pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", uzol "nxs-k8s-s10"                                                                                                               
I1115 07:57:21.639286       1 scheduler_binder.go:279] AssumePodVolumes pre pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", uzol "nxs-k8s-s10": všetky PVC sú priradené a nič sa nedá urobiť                                                                             
I1115 07:57:21.639333       1 factory.go:733] Pokus o priradenie cronjob-cron-events-1573793820-xt6q9 k nxs-k8s-s10

Tu vidíme, že pôvodne plánovač vykonáva filtrovanie a vytvára zoznam zo 3 nód, na ktorých je možné spustiť (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). Následne počíta body podľa niekoľkých parametrov (vrátane BalancedResourceAllocation, LeastResourceAllocation) pre každú z týchto nód s cieľom určiť najvhodnejší uzol. Nakoniec sa plánuje na nód s najvyšším počtom bodov (tu sú dve nody so zhodným počtom bodov 100037, takže sa náhodne vyberie jedna z nich — nxs-k8s-s10).

Záver: ak na nódach pracujú pod, pre ktoré nie sú stanovené obmedzenia, potom pre k8s (z hľadiska spotreby zdrojov) to bude rovné tomu, ako keby na tejto nód neexistovali žiadne pod. Preto, ak máte, podmienečne, pod s náročným procesom (napríklad wowza) a pre neho nie sú stanovené obmedzenia, môže nastať taká situácia, kedy tento pod skutočne zoberie všetky zdroje nód, ale pre k8s sa táto nód považuje za nenáročnú a pri hodnotení (presne v bodoch hodnotenia dostupných zdrojov) získa rovnaký počet bodov ako nód, na ktorej nie sú aktívne pod, čo môže nakoniec viesť k nerovnomernému rozdeleniu záťaže medzi nódami.

Vysťahovanie podu

Ako je známe — každému podu sa priraďuje jedna z 3 QoS tried:

  1. guaranuted — priraďuje sa vtedy, keď pre každý kontajner v pod je pre pamäť a CPU stanovený request a limit, pričom tieto hodnoty musia byť rovnaké
  2. burstable — aspoň jeden kontajner v pod má request a limit, pričom request < limit
  3. best effort — keď ani jeden kontajner v pod nie je obmedzený podľa zdrojov

Pri tom, keď sa na nódach pozoruje nedostatok zdrojov (disku, pamäte), kubelet začína hodnotiť a vysťahovať pod'y podľa určitého algoritmu, ktorý zohľadňuje prioritu podu a jeho QoS triedu. Napríklad, ak ide o RAM, body sú prideľované na základe QoS triedy podľa nasledujúceho princípu:

  • Guaranteed: -998
  • BestEffort: 1000
  • Burstable: min(max(2, 1000 — (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

T.j. pri rovnakej prioritne, kubelet najprv vysťahuje z nód pody s QoS triedou best effort.

Záver: ak chcete znížiť pravdepodobnosť vysťahovania potrebného podu z nód v prípade nedostatku zdrojov na nej, je potrebné vedľa priority tiež zabezpečiť a stanovenie request/limit pre neho.

Mechaniz horizontálneho automatického škálovania podov aplikácie (HPA)

Keď je úlohou automaticky zvyšovať a znižovať počet podov v závislosti od vyžitia zdrojov (systémových - CPU/RAM alebo používateľských - rps), môže nám pri jej riešení pomôcť taká entita k8s ako HPA (Horizontal Pod Autoscaler). Algoritmus je nasledovný:

  1. Určujú sa aktuálne hodnoty sledovaných zdrojov (currentMetricValue)
  2. Určujú sa požadované hodnoty pre zdroj (desiredMetricValue), ktoré pre systémové zdroje sú nastavené pomocou request
  3. Určuje sa aktuálny počet replik (currentReplicas)
  4. Nasledujúcou formulkou sa vypočíta požadovaný počet replik (desiredReplicas)
    desiredReplicas = [ currentReplicas * ( currentMetricValue / desiredMetricValue )]

Pri tom neprebehne škálovanie, keď je pomer (currentMetricValue / desiredMetricValue) blízky 1 (pri tom môžeme nastaviť tolerovanú odchýlku, ktorá je predvolene 0.1).

Zvážme fungovanie hpa na príklade aplikácie app-test (opisanej ako Deployment), kde je potrebné meniť počet replik v závislosti od spotreby CPU:

  • Manifest aplikácie

    kind: Deployment
    apiVersion: apps/v1beta2
    metadata:
     name: app-test
    spec:
     selector:
       matchLabels:
         app: app-test
     replicas: 2
     template:
       metadata:
         labels:
           app: app-test
       spec:
         containers:
         - name: nginx
           image: registry.nixys.ru/generic-images/nginx
           imagePullPolicy: Always
           resources:
             requests:
               cpu: 60m
           ports:
           - name: http
             containerPort: 80
           - name: nginx-exporter
             image: nginx/nginx-prometheus-exporter
             resources:
               requests:
                 cpu: 30m
             ports:
             - name: nginx-exporter
               containerPort: 9113
             args:
             - -nginx.scrape-uri
             - http://127.0.0.1:80/nginx-status

    T.j. vidíme, že pod s aplikáciou sa pôvodne spúšťa v dvoch inštanciách, z ktorých každá obsahuje dva kontejnery nginx a nginx-exporter, pre každý z ktorých je nastavené requests pre CPU.

  • Manifest HPA

    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
     name: app-test-hpa
    spec:
     maxReplicas: 10
     minReplicas: 2
     scaleTargetRef:
       apiVersion: extensions/v1beta1
       kind: Deployment
       name: app-test
     metrics:
     - type: Resource
       resource:
         name: cpu
         target:
           type: Utilization
           averageUtilization: 30

    T.j. vytvorili sme hpa, ktorý bude sledovať Deployment app-test a regulovať počet podov s aplikáciou na základe ukazovateľa CPU (očakávame, že pod by mal spotrebovať 30% percent z požadovaného CPU), pričom počet replik je v rozmedzí 2-10.

    Teraz zvážme mechanizmus fungovania hpa, ak zaťažíme jeden z podov:

     # kubectl top pod
     NAME                                                   CPU(cores)   MEMORY(bytes)
     app-test-78559f8f44-pgs58            101m         243Mi
     app-test-78559f8f44-cj4jz            4m           240Mi

Celkovo máme nasledovné:

  • Požadovaná hodnota (desiredMetricValue) — podľa nastavení hpa je u nás rovná 30%
  • Aktuálna hodnota (currentMetricValue) — pre výpočty controller-manager vypočíta priemernú hodnotu spotreby zdrojov v %, t.j. hypoteticky robí nasledujúce:
    1. Získa absolútne hodnoty metrických údajov pods z metric-servera, t.j. 101m a 4m
    2. Vypočíta priemernú absolútnu hodnotu, t.j. (101m + 4m) / 2 = 53m
    3. Získa absolútnu hodnotu pre požadovanú spotrebu zdrojov (na tento účel sa sčíta request všetkých kontajnerov) 60m + 30m = 90m
    4. Vypočíta priemerné percento spotreby CPU vzhľadom na request podu, t.j. 53m / 90m * 100% = 59%

Teraz máme všetko potrebné na to, aby sme určili, či je potrebné zmeniť počet replik, na to vypočítame koeficient:

ratio = 59% / 30% = 1.96

T.j. počet replik by mal byť zvýšený približne 2-krát a dosiahnuť [2 * 1.96] = 4.

Výstup: Ako si môžete všimnúť, pre fungovanie tohto mechanizmu je nevyhnutnou podmienkou mať requests pre všetky kontajnery v sledovanom pode.

Mechanizmus horizontálneho automatizovaného škálovania uzlov (Cluster Autoscaler)

Aby sa zmiernil negatívny dopad na systém pri nárazoch zaťaženia, nastavenie hpa niekedy nestačí. Napríklad, podľa nastavení v hpa controller manager rozhoduje o tom, že počet replik je potrebné zvýšiť 2-krát, avšak na uzloch nie sú voľné zdroje na spustenie takého počtu pods (t.j. uzol nemôže poskytnúť požadované zdroje podu requests) a tieto pady prechádzajú do stavu Pending.

V tomto prípade, ak má poskytovateľ príslušný IaaS/PaaS (napríklad GKE/GCE, AKS, EKS atď.), môže nám pomôcť taký nástroj, ako Node Autoscaler. Umožňuje nastaviť maximálny a minimálny počet uzlov v klastri a automaticky regulovať aktuálny počet uzlov (prostredníctvom volania API poskytovateľa cloudu na objednanie/odstránenie uzla), keď sa pozoruje nedostatok zdrojov v klastri a pady nemôžu byť naplánované (nachádzajú sa v stave Pending).

Výstup: na možnosť automatizovaného škálovania uzlov je potrebné nastaviť requests v kontajneroch pods, aby k8s mohol správne vyhodnotiť zaťaženie uzlov a následne oznámiť, že na spustenie ďalšieho podu nie sú v klastri zdroje.

Záver

Je dôležité poznamenať, že nastavenie obmedzení zdrojov kontajnera nie je povinnou podmienkou pre úspešné spustenie aplikácie, avšak je to predsa len lepšie z nasledujúcich dôvodov:

  1. Pre presnejšiu prácu scheduleru v oblasti vyvažovania záťaže medzi uzlami k8s
  2. Na zníženie pravdepodobnosti výskytu udalosti 'vysídlenie podu'
  3. Pre funkčnosť horizontálneho automatického škálovania podov aplikácie (HPA)
  4. Pre funkčnosť horizontálneho automatického škálovania uzlov (Cluster Autoscaling) u cloudových poskytovateľov

Čítajte tiež ďalšie články na našom blogu:

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster