Kubernetes: защо е важно да се настрои управлението на ресурсите на системата?

Обикновено възниква необходимост от предоставянето на отделен комплект ресурси за дадено приложение, за да работи коректно и стабилно. Но какво, ако на същите ресурси работят няколко приложения едновременно? Как да осигурим минимално необходимите ресурси за всяко от тях? Как можем да ограничим потреблението на ресурси? Как да разпределим натоварването между нодовете? Как да осигурим функционирането на механизма за хоризонтално мащабиране при увеличаване на натоварването на приложенията?

Kubernetes: защо е важно да се настрои управлението на ресурсите на системата?

Трябва да започнем с основните типове ресурси, които съществуват в системата — това са преди всичко CPU времето и оперативната памет. В манифестите на k8s тези типове ресурси се измерват в следните единици:

  • CPU — в ядра
  • RAM — в байтове

Освен това за всеки ресурс има възможност да се зададат два типа изисквания — requests и limits. Requests — описват минималните изисквания за свободните ресурси на нода за стартиране на контейнера (и на пода като цяло), докато limits задава ригидно ограничение на ресурсите, налични за контейнера.

Важно е да разберем, че в манифеста не е задължително да определяме и двата типа изисквания, като поведението ще бъде следното:

  • Ако е зададено само limits за ресурса, то requests за този ресурс автоматично приема стойност, равна на limits (в това можете да се уверите, като извикате describe на съответната същност). Т.е. фактически работата на контейнера ще бъде ограничена до същото количество ресурси, от което се нуждае за стартирането си.
  • Ако за ресурса е зададено само requests, то не се задават никакви ограничения върху този ресурс — т.е. контейнерът е ограничен само от ресурсите на самия нод.

Съществува и възможност за настройка на управление на ресурсите не само на ниво контейнер, но и на ниво namespace чрез следните същности:

  • LimitRange — описва политиката за ограничаване на ниво контейнер/пода в ns и е необходима, за да опише дефолтните ограничения за контейнер/под, както и да предотврати създаването на излишно големи контейнери/пода (или обратно), да ограничи тяхното количество и да определи възможната разлика в стойностите на limits и requests.
  • ResourceQuotas — описва политиката за ограничаване общо за всички контейнери в ns и се използва, обикновено, за разделяне на ресурсите по среди (полезно е, когато средите не са строго разделени на нива на нодове)

По-долу са предоставени примери за манифести, където се определят ограничения за ресурсите:

  • На ниво конкретен контейнер:

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

    Т.е. в този случай за стартиране на контейнер с nginx ще са необходими поне налични 1G RAM и 0.2 CPU на нода, при това максимум контейнерът може да използва 0.2 CPU и цялата налична RAM на нода.

  • На ниво цяло ns:

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

    Т.е. сумата на всички requests на контейнерите в дефолтното ns не може да надвишава 300m за CPU и 1G за RAM, а сумата на всички limits — 700m за CPU и 2G за RAM.

  • Дефолтни ограничения за контейнерите в 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

    Т.е. в дефолтния namespace за всички контейнери по подразбиране ще бъде зададен request от 100m за CPU и 1G за RAM, limit — 1 CPU и 2G. При това е установено и ограничение на възможните стойности в request/limit за CPU (50m < x < 2) и RAM (500M < x < 4G).

  • Ограничения на ниво подове в ns:

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

    Т.е. за всеки под в дефолтното ns ще бъде установено ограничение от 4 vCPU и 1G.

Сега бих искал да разказвам какви предимства може да ни донесе установяването на тези ограничения.

Механизъм за баланс на натоварването между нодовете

Както е известно, за разпределението на подовете по нодовете отговаря компонент k8s, като scheduler, който работи според определен алгоритъм. Този алгоритъм при избора на оптимален узел за стартиране преминава през две фази:

  1. Филтриране
  2. Ранжиране

Т.е. според описаната политика първоначално се избират нодовете, на които е възможно стартиране на пода въз основа на набор от predicates (включително се проверява дали ресурсите на нода са достатъчни за стартиране на пода — PodFitsResources), а след това за всеки от тези ноди, съгласно priorities Натрупват се точки (включително, колкото повече свободни ресурси има нодата - толкова повече точки се присвояват на нея - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) и се стартира на нодата с най-много точки (ако това условие е изпълнено от няколко ноди, се избира произволна от тях).

В същото време е важно да се разбере, че scheduler при оценка на наличните ресурси на нодата се ръководи от данните, съхранявани в etcd - т.е. от сумата на requested/limit ресурсите на всеки под, стартиран на тази нода, но не и от фактическото потребление на ресурси. Тази информация може да бъде получена в изхода на командата kubectl describe node $NODE, например:

# 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%)

Тук виждаме всички подове, стартирани на конкретната нода, както и ресурсите, които всеки от подовете изисква. Ето как изглеждат логовете на scheduler при стартиране на пода cronjob-cron-events-1573793820-xt6q9 (тази информация в логовете на scheduler ще се появи при настройка на 10-то ниво на логиране в аргументите на командата за стартиране —v=10):

лог

I1115 07:57:21.637791       1 scheduling_queue.go:908] Ще опитам да насроча под nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                           
I1115 07:57:21.637804       1 scheduler.go:453] Опитвам да насроча под: nxs-stage/cronjob-cron-events-1573793820-xt6q9                                                                                                                                                    
I1115 07:57:21.638285       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s5 е разрешено, Възелът изпълнява само 16 от 110 Pods.                                                                               
I1115 07:57:21.638300       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s6 е разрешено, Възелът изпълнява само 20 от 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s3 е разрешено, Възелът изпълнява само 20 от 110 Pods.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s4 е разрешено, Възелът изпълнява само 17 от 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s10 е разрешено, Възелът изпълнява само 16 от 110 Pods.                                                                              
I1115 07:57:21.638365       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s12 е разрешено, Възелът изпълнява само 9 от 110 Pods.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s11 е разрешено, Възелът изпълнява само 11 от 110 Pods.                                                                              
I1115 07:57:21.638385       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s1 е разрешено, Възелът изпълнява само 19 от 110 Pods.                                                                               
I1115 07:57:21.638402       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s2 е разрешено, Възелът изпълнява само 21 от 110 Pods.                                                                               
I1115 07:57:21.638383       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s9 е разрешено, Възелът изпълнява само 16 от 110 Pods.                                                                               
I1115 07:57:21.638335       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s8 е разрешено, Възелът изпълнява само 18 от 110 Pods.                                                                               
I1115 07:57:21.638408       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s13 е разрешено, Възелът изпълнява само 8 от 110 Pods.                                                                               
I1115 07:57:21.638478       1 predicates.go:1369] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s10 е разрешено, условията за антагонизъм на съществуващи подове са удовлетворени.                                                                         
I1115 07:57:21.638505       1 predicates.go:1369] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s8 е разрешено, условията за антагонизъм на съществуващи подове са удовлетворени.                                                                          
I1115 07:57:21.638577       1 predicates.go:1369] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s9 е разрешено, условията за антагонизъм на съществуващи подове са удовлетворени.                                                                          
I1115 07:57:21.638583       1 predicates.go:829] Насрочването на Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 на Възел nxs-k8s-s7 е разрешено, Възелът изпълнява само 25 от 110 Pods.                                                                               
I1115 07:57:21.638932       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Балансирано разпределение на ресурсите, капацитет 39900 милиядни ядра 66620178432 байта памет, обща заявка 2343 милиядни ядра 9640186880 байта памет, оценка 9        
I1115 07:57:21.638946       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Най-малко разпределение на ресурси, капацитет 39900 милиядни ядра 66620178432 байта памет, обща заявка 2343 милиядни ядра 9640186880 байта памет, оценка 8           
I1115 07:57:21.638961       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Балансирано разпределение на ресурсите, капацитет 39900 милиядни ядра 66620170240 байта памет, обща заявка 4107 милиядни ядра 11307422720 байта памет, оценка 9        
I1115 07:57:21.638971       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Балансирано разпределение на ресурсите, капацитет 39900 милиядни ядра 66620178432 байта памет, обща заявка 5847 милиядни ядра 24333637120 байта памет, оценка 7        
I1115 07:57:21.638975       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Най-малко разпределение на ресурси, капацитет 39900 милиядни ядра 66620170240 байта памет, обща заявка 4107 милиядни ядра 11307422720 байта памет, оценка 8           
I1115 07:57:21.638990       1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Най-малко разпределение на ресурси, капацитет 39900 милиядни ядра 66620178432 байта памет, обща заявка 5847 милиядни ядра 24333637120 байта памет, оценка 7           
I1115 07:57:21.639022       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Приоритет за толерантност на замърсявания, оценка: (10)                                                                                                        
I1115 07:57:21.639030       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Приоритет за толерантност на замърсявания, оценка: (10)                                                                                                         
I1115 07:57:21.639034       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Приоритет за толерантност на замърсявания, оценка: (10)                                                                                                         
I1115 07:57:21.639041       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Приоритет на привързаност към възела, оценка: (0)                                                                                                            
I1115 07:57:21.639053       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Приоритет на привързаност към възела, оценка: (0)                                                                                                             
I1115 07:57:21.639059       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Приоритет на привързаност към възела, оценка: (0)                                                                                                             
I1115 07:57:21.639061       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Приоритет за междуподова привързаност, оценка: (0)                                                                                                                   
I1115 07:57:21.639063       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: Приоритет за разпространение на селектори, оценка: (10)                                                                                                                   
I1115 07:57:21.639073       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Приоритет за междуподова привързаност, оценка: (0)                                                                                                                    
I1115 07:57:21.639077       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: Приоритет за разпространение на селектори, оценка: (10)                                                                                                                    
I1115 07:57:21.639085       1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Приоритет за междуподова привързаност, оценка: (0)                                                                                                                    
I1115 07:57:21.639088       1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: Приоритет за разпространение на селектори, оценка: (10)                                                                                                                    
I1115 07:57:21.639103       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: Приоритет за разпространение на селектори, оценка: (10)                                                                                                         
I1115 07:57:21.639109       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: Приоритет за разпространение на селектори, оценка: (10)                                                                                                          
I1115 07:57:21.639114       1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: Приоритет за разпространение на селектори, оценка: (10)                                                                                                          
I1115 07:57:21.639127       1 generic_scheduler.go:781] Хост nxs-k8s-s10 => Оценка 100037                                                                                                                                                                            
I1115 07:57:21.639150       1 generic_scheduler.go:781] Хост nxs-k8s-s8 => Оценка 100034                                                                                                                                                                             
I1115 07:57:21.639154       1 generic_scheduler.go:781] Хост nxs-k8s-s9 => Оценка 100037                                                                                                                                                                             
I1115 07:57:21.639267       1 scheduler_binder.go:269] AssumePodVolumes за под "nxs-stage/cronjob-cron-events-1573793820-xt6q9", възел "nxs-k8s-s10"                                                                                                               
I1115 07:57:21.639286       1 scheduler_binder.go:279] AssumePodVolumes за под "nxs-stage/cronjob-cron-events-1573793820-xt6q9", възел "nxs-k8s-s10": всички PVCs свързани и нищо не трябва да се прави                                                                             
I1115 07:57:21.639333       1 factory.go:733] Опит за свързване на cronjob-cron-events-1573793820-xt6q9 с nxs-k8s-s10

Тук виждаме, че в началото scheduler извършва филтриране и създава списък от 3 ноди, на които е възможно да се стартира (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10). След това се извършва броене на точки по няколко параметра (включително BalancedResourceAllocation, LeastResourceAllocation) за всяка от тези ноди, с цел да се определи най-подходящият възел. В крайна сметка подът се планира на нодата с най-много точки (тук веднага две ноди имат еднакъв брой точки 100037, затова се избира случайна от тях — nxs-k8s-s10).

Извод: ако на нодата работят подове, за които не са зададени ограничения, то за k8s (от гледна точка на потреблението на ресурси) това ще бъде равносилно на ситуация, в която на тази нода такива подове изобщо не присъстват. Затова, ако условно имате pod с изискващ процес (например, wowza) и за него не са зададени ограничения, е възможно да възникне ситуация, в която фактически този под е изял всичките ресурси на нодата, но за k8s, тази нода се счита за ненатоварена и ще получава същото количество точки при ранжиране (точно в раздела с оценка на наличните ресурси), както и нодата, на която няма работещи подове, което в крайна сметка може да доведе до неравномерно разпределение на натоварването между нодите.

Изгонване на пода

Както е известно — на всеки под се присвоява един от 3 QoS-класа:

  1. guaranuted — назначава се тогава, когато за всеки контейнер в пода за памет и CPU са зададени request и limit, като тези стойности трябва да съвпадат
  2. burstable — поне един контейнер в пода има request и limit, при това request < limit
  3. best effort — когато нито един контейнер в пода не е ограничен по ресурси

В същото време, когато на нодата има недостиг на ресурси (диск, памет), kubelet започва да ранжира и изгонва подове по определен алгоритъм, който взима предвид приоритета на пода и неговия QoS-клас. Например, ако става въпрос за RAM, то на основание QoS клас се начисляват точки по следния принцип:

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

Т.е. при еднакъв приоритет, kubelet ще изгонва от нодата подовете с QoS-клас best effort на първо място.

Извод: ако искате да намалите вероятността от изгонване на необходимия под от нодата при недостиг на ресурси на нея, то наред с приоритета трябва да се погрижите и за задаването на request/limit за него.

Механизм за хоризонтално автоматично мащабиране на подовете на приложението (HPA)

Когато задачата е автоматично да увеличи или намали броя на подовете в зависимост от използването на ресурси (системни — CPU/RAM или потребителски — rps), в решаването на този проблем може да помогне такава сущност на k8s като HPA (Horizontal Pod Autoscaler). Алгоритъмът на който е следният:

  1. Определят се текущите показатели на наблюдавания ресурс (currentMetricValue)
  2. Определят се желаните стойности за ресурса (desiredMetricValue), които за системните ресурси се задават чрез request
  3. Определя се текущият брой на репликите (currentReplicas)
  4. По следната формула се изчислява желаното количество реплики (desiredReplicas)
    desiredReplicas = [ currentReplicas * ( currentMetricValue / desiredMetricValue )]

При това мащабиране няма да се случи, когато коефициентът (currentMetricValue / desiredMetricValue) е близък до 1 (при това допустимата грешка можем да задаваме сами, по подразбиране тя е равна на 0.1).

Нека разгледаме работата на hpa на примера на приложението app-test (описано като Deployment), където е необходимо да се промени количеството реплики в зависимост от потреблението на CPU:

  • Манифест на приложението

    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

    Т.е. виждаме, че подът с приложението първоначално се стартира в два екземпляра, всеки от които съдържа два контейнера nginx и nginx-exporter, за всеки от които е зададен requests за CPU.

  • Манифест на 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

    Т.е. създадохме hpa, който ще следи за Deployment app-test и ще регулира количеството подове с приложението на база показателя cpu (очакваме, че подът трябва да консумира 30% от заявеното му CPU), при това количеството реплики варира в диапазона 2-10.

    Сега, нека разгледаме механизма на работа на hpa, ако натоварим един от подовете:

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

И така, имаме следното:

  • Желаната стойност (desiredMetricValue) — съгласно настройките на hpa, е 30%
  • Текущата стойност (currentMetricValue) — за изчисление, controller-manager изчислява средната стойност на потребление на ресурса в %, т.е. условно прави следното:
    1. Получава абсолютни стойности на метриките на подовете от metric-сервера, т.е. 101m и 4m
    2. Изчислява средното абсолютното значение, т.е. (101m + 4m) / 2 = 53m
    3. Получава абсолютната стойност за желаното потребление на ресурса (за това се сумират requests на всички контейнери) 60m + 30m = 90m
    4. Изчислява средния процент на потребление на CPU спрямо requests на пода, т.е. 53m / 90m * 100% = 59%

Сега имаме всичко необходимо, за да определим дали е необходимо да променим броя на репликите, за това изчисляваме коефициента:

ratio = 59% / 30% = 1.96

Т.е. броят на репликите трябва да бъде увеличен приблизително два пъти и да бъде [2 * 1.96] = 4.

Изход: Както може да се види, за да работи този механизъм, е необходимо условие също така да има requests за всички контейнери в наблюдавания под.

Механизмът за хоризонтално автоматично скалиране на нодовете (Cluster Autoscaler)

За да се неутрализира негативното влияние върху системата при пикова натовареност, наличието на настроен hpa често е недостатъчно. Например, съгласно настройките в hpa controller manager взема решение, че броят на репликите е необходимо да се увеличи два пъти, но на нодовете няма свободни ресурси за стартиране на такова количество подове (т.е. нодата не може да предостави исканите ресурси на пода requests) и тези подове преминават в състояние Pending.

В този случай, ако провайдърът има съответното IaaS/PaaS (например, GKE/GCE, AKS, EKS и т.н.), такъв инструмент като Node Autoscalerможе да ни помогне. Той позволява да зададете максимален и минимален брой ноди в кластера и автоматично да регулира текущия брой ноди (чрез обращение към API на облачния провайдър за поръчка/изтриване на нода), когато се наблюдава недостиг на ресурси в кластера и подовете не могат да бъдат планирани (намират се в състояние Pending).

Изход: за възможността за автоматично скалиране на нодовете е необходимо да се задават requests в контейнери на подовете, за да може k8s правилно да оценява натоварването на нодовете и съответно да сигнализира, че за стартиране на следващия под в кластера няма ресурси.

Заключение

Трябва да се отбележи, че настройката на ограничения за ресурсите на контейнера не е задължително условие за успешното стартиране на приложението, но все пак е добре да се направи по следните причини:

  1. За по-точна работа на scheduler в частта за балансиране на натоварването между нодовете в k8s
  2. За намаляване на вероятността от възникване на събитие "изгонване на пода"
  3. За работата на хоризонталното автоматично мащабиране на подовете на приложението (HPA)
  4. За работата на хоризонталното автоматично мащабиране на нодовете (Cluster Autoscaling) при облачните доставчици

Също така прочетете други статии в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster