Окрім 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 – то “вбиває” їх (EvictedByVPA
Kubernetes 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-серверу.