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

Започваме с основните типове ресурси в системата — това, разбира се, е процесорното време и оперативната памет. В манифестите на 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, който работи по определен алгоритъм. Този алгоритъм при избора на оптимален възел за стартиране преминава през две стадии:
- Филтрация
- Ранжиране
Т.е. съгласно описаната политика първоначално се избират възлите, на които е възможно стартиране на пода въз основа на набора 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-класа:
- гарантиран — присвоява се, когато за всеки контейнер в пода за памет и CPU е зададен request и limit, като тези стойности трябва да съвпадат
- бурстабилен — поне един контейнер в пода има request и limit, при това request < limit
- най-добро усилие — когато нито един контейнер в пода не е ограничен по ресурси
При това, когато на нода се наблюдава недостиг на ресурси (диск, памет), 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). Алгоритъмът е следният:
- Определят се текущите показания на наблюдавания ресурс (currentMetricValue)
- Определят се желаните стойности за ресурса (desiredMetricValue), които за системните ресурси се задават чрез request
- Определя се текущият брой реплики (currentReplicas)
- По следната формула се изчислява желаното количество реплики (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 изчислява средното потребление на ресурс в %, т.е. условно прави следното:
- Получава абсолютните стойности на метриките на подовете от metric-сервера, т.е. 101m и 4m
- Изчислява средната абсолютна стойност, т.е. (101m + 4m) / 2 = 53m
- Получава абсолютната стойност за желаното потребление на ресурс (като се сумират requests на всички контейнери) 60m + 30m = 90m
- Изчислява средния процент на потребление на 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 правилно да оцени натовареността на нодите и съответно да съобщи, че за стартиране на поредния под в клъстера няма ресурси.
Заключение
Следва да се отбележи, че задаването на ограничения за ресурсите на контейнера не е задължително условие за успешното стартиране на приложението, но все пак е по-добре да се направи по следните причини:
- За по-точна работа на scheduler в частта за балансировка на натоварването между възлите на k8s
- За намаляване на вероятността от възникване на събитие "изселване на пода"
- За работа на хоризонталното автоматично мащабиране на подовете на приложението (HPA)
- За работа на хоризонталното автоматично мащабиране на възлите (Cluster Autoscaling) при облачни доставчици
Също така прочетете и други статии в нашия блог:
Източник: habr.com
