Окрім Horizontal Pod Autoscaler (HPA), який створює додаткові поди якщо наявні починають використовувати більше CPU/Memory, ніж налаштовано у лімітах HPA, існує і Vertical Pod Autoscaler (VPA), який працює за іншою схемою: замість горизонтального масштабування, тобто збільшення кількості подів, він змінює resources.requests поду, що призводить до того, что Kubernetes Scheduler “переселяє” цей под на іншу WorkerNode, якщо на поточній не вистачає ресурсів.
Тобто, VPA постійно моніторить споживання ресурсів контейнерами у подах, і змінює значення відповідно до актуального споживання ресурсів, і може як збільшувати значення реквестів, так і зменшувати його, таким чином автоматично налаштовуючи потреби пода, щоб уникнути нераціонального використання ресурсів інстансів Kubernetes-кластеру та забезпечити сам под достатнім CPU time і пам’ятю.
Зміст
Компоненти Vertical Pod Autoscaler
Після деплою VPA, він створює три поди для своєї роботи:
recommender: займається моніторингом використання ресурсів подами, і видає свої рекомендації по значенню cpu/mem requests, які треба встановити подамupdater: моніторить поди та їхні поточні значення cpu/mem requests, і якщо ці значення не збігаються зі значеннями від recommender – то “вбиває” їх (EvictedByVPAKubernetes event), щоб контролери Kubernetes перестворили їх з потрібними значеннямиadmission-plugin: займається власне тим, що встановлює значення реквестів для нових подів, або тих, що були перестворенні після того, як updater кільнув їх
Обмеження Vertical Pod Autoscaler
При використанні VPA, майте на увазі, що:
- VPA не відслідковує процесс перестворення подів, тобто після того, як под був evicted – то його створення вже цілком залежить від Kubernetes. Якщо у кластері на момент перестворення подів не буде вільних WorkerNodes, то под може залишитиcь у Pending статусі, тому бажано мати Cluster Autoscaler або Karpenter, який запустить новую ноду
- VPA не може використовуватись одночасно з HPA, якщо скейлінг налаштовано на CPU/Memory, але їх можна використовувати, якщо HPA налаштований на custom metrics
- також майте на увазі сам факт того, що при роботі VPA перестворює поди, тобто якщо у вас немає якогось fault-tolerant у вигляді додаткових подів, які зможуть взяти на себе навантаження на час перестворення поду – то сервіс буде недоступний, допоки відповідний контроллер (ReplicaSet, StatefulSet, etc) не запустить новий інстанс поду
Див більше у Known limitations.
Запуск Vertical Pod Autoscaler
При роботі, VPA покладається на Kubernetes Metrics Server для отримання значень CPU/Mem подів, але також може використовувати Prometheus, див. How can I use Prometheus as a history provider for the VPA recommender.
Встановлення Metrics Server
Оскільки тестити VPA будемо у Minikube, то встановимо плагін Metrics Server:
[simterm]
$ minikube addons enable metrics-server
[/simterm]
Або у разі звичайного Kubernetes-кластеру – з Helm-чарту:
[simterm]
$ helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ $ helm -n kube-system upgrade --install metrics-server metrics-server/metrics-server
[/simterm]
І дивимось, чи працює kubectl top pod, який бере дані саме з Metrics Server:
[simterm]
$ kubectl top pod --all-namespaces NAMESPACE NAME CPU(cores) MEMORY(bytes) kube-system etcd-minikube 83m 33Mi kube-system kube-apiserver-minikube 249m 254Mi kube-system kube-controller-manager-minikube 54m 45Mi kube-system kube-scheduler-minikube 26m 22Mi
[/simterm]
Встановлення Vertical Pod Autoscaler
Також використовуємо Helm-чарт – cowboysysop/vertical-pod-autoscaler:
[simterm]
$ helm repo add cowboysysop https://cowboysysop.github.io/charts/ $ helm -n kube-system upgrade -install vertical-pod-autoscaler cowboysysop/vertical-pod-autoscaler
[/simterm]
Перевіряємо поди:
[simterm]
$ kk -n kube-system get pod -l app.kubernetes.io/name=vertical-pod-autoscaler NAME READY STATUS RESTARTS AGE vertical-pod-autoscaler-admission-controller-655f9b57d7-q85kc 1/1 Running 0 58s vertical-pod-autoscaler-recommender-7d964f7894-k87hb 1/1 Running 0 58s vertical-pod-autoscaler-updater-7ff97c4d85-vfjkj 1/1 Running 0 58s
[/simterm]
Та його CustomResourceDefinitions:
[simterm]
$ kk get crd NAME CREATED AT verticalpodautoscalercheckpoints.autoscaling.k8s.io 2023-04-27T08:38:16Z verticalpodautoscalers.autoscaling.k8s.io 2023-04-27T08:38:16Z
[/simterm]
Тепер все готове, щоб починати ним користуватись.
Приклади роботи з Vertical Pod Autoscaler
В репозиторії VPA є директорія examples, яка містить приклади маніфестів, наприклад у файлі hamster.yaml є приклад налаштованого VPA та тестового Deployment.
Але давайте створимо свої маніфести, та задеплоїмо ресурси окремо.
Спочатку Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hamster
spec:
selector:
matchLabels:
app: hamster
replicas: 2
template:
metadata:
labels:
app: hamster
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: hamster
image: registry.k8s.io/ubuntu-slim:0.1
resources:
requests:
cpu: 100m
memory: 50Mi
command: ["/bin/sh"]
args:
- "-c"
- "while true; do timeout 0.5s yes >/dev/null; sleep 0.5s; done"
Тут маємо створити два поди, яким задаємо requests у 100 Milicpu та 50 Megabyte memory.
Деплоймо:
[simterm]
$ kubectl apply -f hamster-deployment.yaml deployment.apps/hamster created
[/simterm]
За хвилину-дві перевіряємо ресурси, які реально споживаються подами:
[simterm]
$ kk top pod NAME CPU(cores) MEMORY(bytes) hamster-65cd4dd797-fq9lq 498m 0Mi hamster-65cd4dd797-lnpks 499m 0Mi
[/simterm]
Тепер додамо VPA:
apiVersion: "autoscaling.k8s.io/v1"
kind: VerticalPodAutoscaler
metadata:
name: hamster-vpa
spec:
# recommenders field can be unset when using the default recommender.
# When using an alternative recommender, the alternative recommender's name
# can be specified as the following in a list.
# recommenders:
# - name: 'alternative'
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: hamster
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 50Mi
maxAllowed:
cpu: 1
memory: 500Mi
controlledResources: ["cpu", "memory"]
Деплоїмо:
[simterm]
$ kubectl apply -f hamster-vpa.yaml verticalpodautoscaler.autoscaling.k8s.io/hamster-vpa created
[/simterm]
Перевіряємо сам VPA:
[simterm]
$ kk get vpa NAME MODE CPU MEM PROVIDED AGE hamster-vpa Auto 14s
[/simterm]
І за хвилину-дві, коли спрацює recommender:
[simterm]
$ kk get vpa NAME MODE CPU MEM PROVIDED AGE hamster-vpa Auto 587m 262144k True 43s
[/simterm]
І ще за хвилину – перевіряємо поди, коли спрацює Updater:
[simterm]
$ kk get pod NAME READY STATUS RESTARTS AGE hamster-65cd4dd797-fq9lq 1/1 Terminating 0 3m43s hamster-65cd4dd797-hc9cn 1/1 Running 0 13s hamster-65cd4dd797-lnpks 1/1 Running 0 3m43s
[/simterm]
Та перевіряємо значення requests нового поду:
[simterm]
$ kubectl get pod hamster-65cd4dd797-hc9cn -o yaml | yq '.spec.containers[].resources'
{
"requests": {
"cpu": "587m",
"memory": "262144k"
}
}
[/simterm]
Тепер, як ми побачили VPA в дії, давайте трохи розберемось з його API та доступними параметрами.
Vertical Pod Autoscaler API reference та параметри
Повний опис див. у API reference, а зараз просто зробимо describe нашого існуючого VPA, щоб зрозуміти, що там взагалі є:
[simterm]
$ kubectl describe vpa/hamster-vpa
Name: hamster-vpa
Namespace: default
Labels: <none>
Annotations: <none>
API Version: autoscaling.k8s.io/v1
Kind: VerticalPodAutoscaler
Metadata:
Creation Timestamp: 2023-04-27T09:05:41Z
Generation: 61
Resource Version: 7016
UID: 227c0ce6-7f86-4bff-b9b5-d88914f90bec
Spec:
Resource Policy:
Container Policies:
Container Name: *
Controlled Resources:
cpu
memory
Max Allowed:
Cpu: 1
Memory: 500Mi
Min Allowed:
Cpu: 100m
Memory: 50Mi
Target Ref:
API Version: apps/v1
Kind: Deployment
Name: hamster
Update Policy:
Update Mode: Auto
Status:
Conditions:
Last Transition Time: 2023-04-27T09:06:11Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: hamster
Lower Bound:
Cpu: 569m
Memory: 262144k
Target:
Cpu: 587m
Memory: 262144k
Uncapped Target:
Cpu: 587m
Memory: 262144k
Upper Bound:
Cpu: 1
Memory: 262144k
Events: <none>
[/simterm]
Або у “чистому” yaml:
[simterm]
$ kubectl get vpa/hamster-vpa -o yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
...
spec:
resourcePolicy:
containerPolicies:
- containerName: '*'
controlledResources:
- cpu
- memory
maxAllowed:
cpu: 1
memory: 500Mi
minAllowed:
cpu: 100m
memory: 50Mi
targetRef:
apiVersion: apps/v1
kind: Deployment
name: hamster
updatePolicy:
updateMode: Auto
status:
...
recommendation:
containerRecommendations:
- containerName: hamster
lowerBound:
cpu: 570m
memory: 262144k
target:
cpu: 587m
memory: 262144k
uncappedTarget:
cpu: 587m
memory: 262144k
upperBound:
cpu: "1"
memory: 262144k
[/simterm]
І тепер розлянемо параметри з нашого VPA та інші, которі можуть бути нам корисні в майбутньому:
spec(VerticalPodAutoscalerSpec):targetRef: тип контролеру, який відповідає за поди, которі будуть скейлитись цим VPAupdatePolicy(PodUpdatePolicy): задає, чи будуть рекомендації застосовані при створенні поду, і чи будуть застосовуватись протягом його роботиupdateMode: може мати значення “Off“, “Initial“, “Recreate” та “Auto” (дефолтне значення):Off: не буде застосовувати нові значення, а тільки внесе їх у полеstatus(див. нижче)Initial: застосує значення тільки при створенні подуRecreate: застосує значення при створенні поду і під час його роботиAuto: на цей час виконує теж саме, щоRecreate(хоча ще чотири роки тому наче казали, що планується при “Auto” міняти реквести без рестарту)
minReplicas: мінімальна кількість подів, які мають бути в статусі Running, щоб VPA Updater виконав Pod Eviction для застосування нових значень уrequests
resourcePolicy(PodResourcePolicy): задає параметри того, як CPU та Memory requests будуть налаштовуватись для конкретних контейнерів, якщо не задано – то VPA застосує нові значення для всіх контейнерів в подіcontainerPolicies(ContainerResourcePolicy): налаштування для конкретних контейнерів, або для всіх, які не мають власних параметрів, за допомогоюcontainerName = '*'containerName: ім’я контейнеру, для якого описуються параметриmode: задає, чи будуть рекомендації застосовані при створенні контейнеру, і чи будуть застосовуватись протягом його роботи, може мати значення “Off” або “Auto” (дефолтне значення)minAllowedтаmaxAllowed: задає мінімальні та максимальні значення для CPU/Memory requestsControlledResources: для яких саме ресурсів застосовувати рекомендації –ResourceCPU,ResourceMemory, або обидва (дефолтне, якщо не вказано жодного)
status(VerticalPodAutoscalerStatus): останні рекуомендації від Recommenderrecommendation(RecommendedPodResources): останні рекомендовані значення CPU/MemorycontainerRecommendations(RecommendedContainerResources): рекомендації для кожного контейнеруcontainerName: ім’я контейнеруtarget: рекомендовані значення для контейнеруlowerBound: мінімально рекомендовані значення для контейнеруupperBound: максимально рекомендовані значення для контейнеруuncappedTarget: останні рекомендовані значення CPU/Memory на основі реального споживання ресурсів без врахуванняContainerResourcePolicy(тобто безminAllowedтаmaxAllowed), не враховується Recommender, відображається тільки для інформації
На цьому поки все.
З VPA бувають проблеми, але в цілому у нас в продакшені працють без нарікань, наприклад – міняються значення для подів Prometheus-серверу.




