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

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

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

Започваме с основните типове ресурси в системата — това, разбира се, е процесорното време и оперативната памет. В манифестите на k8s тези типове ресурси се измерват в следните единици:

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

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

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

  • Ако е зададено само limits за ресурса, requests за този ресурс автоматично приема стойност, равна на limits (можете да се уверите в това, вызванявайки описанието на единствения елемент). Т.е. фактическата работа на контейнера ще бъде ограничена до същото количество ресурси, което той изисква за стартиране.
  • Ако за ресурса е зададено само 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

    Т.е. сумата на всички request контейнери в дефолтния ns не може да надвишава 300m за CPU и 1G за RAM, а сумата на всички limit — 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] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s5 е позволено, възелът работи само с 16 от 110 пода.                                                                               
I1115 07:57:21.638300       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s6 е позволено, възелът работи само с 20 от 110 пода.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s3 е позволено, възелът работи само с 20 от 110 пода.                                                                               
I1115 07:57:21.638322       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s4 е позволено, възелът работи само с 17 от 110 пода.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s10 е позволено, възелът работи само с 16 от 110 пода.                                                                              
I1115 07:57:21.638365       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s12 е позволено, възелът работи само с 9 от 110 пода.                                                                               
I1115 07:57:21.638334       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s11 е позволено, възелът работи само с 11 от 110 пода.                                                                              
I1115 07:57:21.638385       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s1 е позволено, възелът работи само с 19 от 110 пода.                                                                               
I1115 07:57:21.638402       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s2 е позволено, възелът работи само с 21 от 110 пода.                                                                               
I1115 07:57:21.638383       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s9 е позволено, възелът работи само с 16 от 110 пода.                                                                               
I1115 07:57:21.638335       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s8 е позволено, възелът работи само с 18 от 110 пода.                                                                               
I1115 07:57:21.638408       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s13 е позволено, възелът работи само с 8 от 110 пода.                                                                               
I1115 07:57:21.638478       1 predicates.go:1369] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s10 е позволено, настоящите условия за антингажираност на подовете са изпълнени.                                                                         
I1115 07:57:21.638505       1 predicates.go:1369] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s8 е позволено, настоящите условия за антингажираност на подовете са изпълнени.                                                                          
I1115 07:57:21.638577       1 predicates.go:1369] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s9 е позволено, настоящите условия за антингажираност на подовете са изпълнени.                                                                          
I1115 07:57:21.638583       1 predicates.go:829] Планирането на под nxs-stage/cronjob-cron-events-1573793820-xt6q9 на възел nxs-k8s-s7 е позволено, възелът работи само с 25 от 110 пода.                                                                               
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] Приемам обеми за пода "nxs-stage/cronjob-cron-events-1573793820-xt6q9", възел "nxs-k8s-s10"                                                                                                               
I1115 07:57:21.639286       1 scheduler_binder.go:279] Приемам обеми за пода "nxs-stage/cronjob-cron-events-1573793820-xt6q9", възел "nxs-k8s-s10": всички PVC са свързани и нищо не остава за обработка                                                                             
I1115 07:57:21.639333       1 factory.go:733] Опитвам да свържа cronjob-cron-events-1573793820-xt6q9 с nxs-k8s-s10

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

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

Изселване на пода

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

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

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

  • Гарантиран: -998
  • Най-добро усилие: 1000
  • Бурстабилен: min(max(2, 1000 — (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

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

Извод: ако искате да намалите вероятността от изселване на нужния под от нода в случай на недостиг на ресурси на него, то наред с приоритета необходимо е също така да се погрижите и за задаването на 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 спрямо request на пода, т.е. 53m / 90m * 100% = 59%

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

ratio = 59% / 30% = 1.96

Т.е. броят на репликите трябва да бъде увеличен приблизително 2 пъти и да бъде [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