И почему не стоит его использовать в автоматическом режиме



Вертикальное автомасштабирование подов (Vertical Pod Autoscaling) — одна из крутых функций Kubernetes, которую недостаточно часто используют. И на это есть серьезные причины.
Kubernetes был создан для горизонтального масштабирования, и изначально вертикальное масштабирование подов не казалось очень-то хорошей идеей. Вместо этого более логичным считалось создание копии пода в случае, когда появлялась дополнительная нагрузка.


Однако для этого требовалось серьезно оптимизировать ресурсы, и если вы не настроили под должным образом, установив правильный запрос ресурсов и конфигурацию ограничений, это могло привести либо к слишком частому удалению подов, либо к трате большого количества полезных ресурсов. Если вы назначите своему поду слишком мало ресурсов запроса, ему может не хватить ресурсов для запуска, а если вы назначите слишком много, он будет впустую растрачивать полезные ресурсы, которые могли бы понадобиться другим подам.


Идея использования Kubernetes заключается в том, чтобы упаковать как можно больше контейнеров в максимально маленькую инфраструктуру (очевидно, это требует от вас сохранения буфера на случай сбоя узла, но вы поняли суть). Методом проб и ошибок разработчики и системные администраторы искали оптимальное значение запросов ресурсов и ограничений. Их настройка требовала значительного контроля и понимания, как эффективно их использовать — через сравнительное тестирование или через общее наблюдение за производственным использованием и трафиком.


Все усложняется, когда трафик прерывист, а использование ресурсов не оптимально. С ростом числа контейнеров в микросервисной архитектуре, становится неординарным понимание паттернов утилизации ресурсов, так как системные администраторы сфокусированы на стабильности и в конечном итоге устанавливают запросы ресурсов намного выше того уровня, который реально нужен.


Kubernetes нашел решение этой проблемы в вертикальном автомасштабировании подов. Давайте разберемся, что оно делает и когда его стоит использовать. А затем рассмотрим небольшой пример, чтобы увидеть этот инструмент в действии.


Как работает инструмент вертикального автомасштабирования подов (Vertical Pod Autoscaler, VPA)


VPA использует два основных компонента для того, чтобы автомасштабирование работало. Алгоритм следующий:


  • Рекомендательный сервис VPA проверяет историю использования ресурсов и текущий шаблон использования и рекомендует идеальное значение ресурса запросов.
  • Если вы установили автоматический режим обновлений, автоматический регулятор VPA исключит работающий под и, основываясь на новом значении ресурса запросов, создаст новый.
  • Автоматический регулятор VPA также масштабирует значение предельных ограничений в отношении изначально определенных ограничений (если такие были). Однако он не оставляет рекомендаций по тому, каким должно быть предельно допустимое значение.

Для ограничения ресурсов нет определенного значения — автомасштабирование просто будет его поднимать. И все же, если вы хотите подстраховаться на случай утечки данных, вы можете установить значения максимального ресурса (Max Resource, MR) в Спецификаторе VPA.


Манифест VPA


Давайте взглянем на представленный ниже пример манифеста VPA:


apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  name: nginx-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment
    name:       nginx
  updatePolicy:
    updateMode: "On"
  resourcePolicy:
    containerPolicies:
    - containerName: "nginx"
      minAllowed:
        cpu: "250m"
        memory: "100Mi"
      maxAllowed:
        cpu: "2000m"
        memory: "2048Mi"
    - containerName: "istio-proxy"
      mode: "Off"

Как и в любом манифесте, в нем есть поля apiVersion, kind, metadata и spec.


В поле spec мы видим раздел targetRef, который определяет объект, к которому применяется VPA. Раздел updatePolicy определяет, будет ли этот VPA лишь рекомендовать или рекомендовать и автомасштабировать, основываясь на свойстве updateMode. Если updateMode установлен на Auto, он автомасштабирует поды вертикально, если Off, он просто реко��ендует идеальные значения запроса ресурсов.


Раздел resourcePolicy позволяет нам задать containerPolicies для каждого контейнера со значениями ресурсов minAllowed и maxAllowed. Это крайне важно, чтобы обезопаситься от утечек памяти. Вы также можете отключить рекомендации по ресурсам и автоматическое масштабирование для определенного контейнера в поде, что обычно встречается в случае сайдкаров Istio или InitContainers.


Ух ты! Это было что-то. В следующей части рассмотрим некоторые ограничения.


Ограничения


Вертикальное автомасштабирование подов, конечно, имеет свои ограничения.


Его нельзя использовать вместе с горизонтальным автомасштабированием подов.


Поскольку вертикальное автомасштабирование подов автом��тически изменяет запросы и предельные значения, нельзя использовать его вместе с инструментом горизонтального автомасштабирования (Horizontal Pod Autoscaler, HPA), потому что HPA полагается на CPU и использование памяти, чтобы горизонтально масштабировать поды. Исключением из этого правила может быть ситуация, когда вы используете HPA, который полагается на пользовательские и внешние метрики для масштабирования подов.


Для его работы требуется как минимум две работоспособные реплики подов.


Это ограничение в первую очередь подрывает цель вертикального автомасштабирования и является причиной, по которой оно не часто используется. Поскольку VPA разрушает под и воссоздает его для проведения вертикального автомасштабирования, ему требуется минимум две работоспособные реплики пода, чтобы гарантировать отсутствие перебоев сервиса. Это создает ненужные сложности архитектуры stateful-приложений, и вам придется посмотреть на архитектуру реплики. Для приложений с распределенной структурой использование HPA может быть лучше, чем VPA.


Минимальная выделенная память по умолчанию — 250 MiB.


VPA выделяет минимум 250 MiB памяти вне зависимости от того, что вы указали. И хотя это значение по умолчанию можно исправить на глобальном уровне, VPA становится непрактичным для приложений, которые потребляют меньше памяти.


VPA нельзя использовать с отдельными подами.


VPA работает только с Deployments, StatefulSets, DaemonSets, ReplicaSets и т.д. Его нельзя использовать с изолированным подом, у которого нет владельца. Это не очень существенное ограничение, поскольку большинство разработчиков не используют изолированные поды, но его стоило упомянуть.


Использование VPA в режиме рекомендаций


До сих пор лучший из всех возможных вариантов использования VPA в производственной среде — использование его в режиме рекомендации. Этот режим очень помогает понимать, каковы оптимальные значения запроса ресурсов и как они могут изменяться со временем.


Как только вы это определите, вы сможете собрать эти метрики при помощи оператора Kubernetes или Kubectl и отправить их в инструмент мониторинга и визуализации, как Prometheus, Grafana или стек ELK, чтобы получить важную аналитическую информацию.


Вы можете использовать эту информацию для изменения размеров подов в соответствии с рекомендациями, выбрав часы минимальной нагрузки в течение дня, чтобы ваша работа не повлияла на пользователей и бизнес. И это может также стать частью стратегии непрерывного улучшения.


Я бы не рекомендовал запускать VPA в авторежиме в производственной среде, потому что это относительно новый инструмент, который все еще активно развивается. Меньше всего вам нужен отказ в обслуживании из-за того, что VPA слишком часто удаляет ваши поды. Если вы не знаете наверняка, что делаете, лучше не начинать сразу использовать VPA в производственной среде.


При этом вы всегда можете поэкспериментировать с VPA в среде разработки и проверить, как он ведет себя при возрастающей нагрузке. Вы легко можете выяснить максимальное количество ресурсов, которые может потреблять ваш под, запустив нагрузочный тест, который мы увидим в следующей части.


Практика


Для этого упражнения я бы использовал GKE с включенным VPA. GKE поддерживает VPA только в региональных кластерах.


Убедитесь, пожалуйста, что вы включили VPA в своем кластере либо через контроллер Admission, если вы используете самоуправляемую настройку, либо через настройки вашего облачного провайдера, если используется управляемый кластер.


Итак, начнем. Первым делом создадим deployment Nginx c запросом по умолчанию 250 MiB памяти и 100m CPU.


$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
 labels:
   app: nginx
 name: nginx
spec:
 replicas: 2
 selector:
   matchLabels:
     app: nginx
 strategy: {}
 template:
   metadata:
     labels:
       app: nginx
   spec:
     containers:
     - image: nginx
       name: nginx
       resources:
         requests:
           cpu: 100m
           memory: 250Mi
EOF

Теперь нам надо представить deployment как сервис LoadBalancer.


kubectl expose deployment nginx --type=LoadBalancer --port 80

Подождем, пока облачный провайдер включит балансировщик нагрузки и получит IP балансировщика нагрузки.


$ kubectl get svc nginx
NAME    TYPE           CLUSTER-IP   EXTERNAL-IP      PORT(S)        AGE
nginx   LoadBalancer   10.4.1.4     34.121.204.234   80:30750/TCP   46s

Теперь создадим VPA с updateMode: "Off". Это не запустит вертикальное автомасштабирование, но предоставит рекомендации.


$ cat <<EOF | kubectl apply -f
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
 name: nginx-vpa
spec:
 targetRef:
   apiVersion: "apps/v1"
   kind:       Deployment
   name:       nginx
 updatePolicy:
   updateMode: "Off"
 resourcePolicy:
  containerPolicies:
   - containerName: "nginx"
    minAllowed:
       cpu: "250m"
       memory: "100Mi"
     maxAllowed:
       cpu: "2000m"
       memory: "2048Mi"
EOF

Теперь ��роведем некоторые нагрузочные тесты, чтобы проверить, какие рекомендации мы получим с нагрузкой. Для этого теста я воспользуюсь утилитой hey:


hey -z 300s -c 1000 http://34.121.204.234

Это запускает запросы в течение 300 секунд с использованием 1000 параллельных потоков — серьезная нагрузка на сервис.


Запустите следующую команду, чтобы получить рекомендации по описанию VPA:


kubectl describe vpa nginx-vpa

Если мы некоторое время понаблюдаем за VPA, мы увидим, что он будет постепенно рекомендовать увеличивать запросы ресурсов:



Взглянув на секцию рекомендации, вы увидите несколько предложений.


  • Цель (Target): это реальное значение, которое VPA будет использовать, удаляя текущий под и создавая новый. Если вы очищаете эти метрики, всегда надо отслеживать целевое значение.
  • Нижняя граница (Lower Bound): отражает нижнюю границу, при которой запускается изменение размера. Если загрузка вашего пода опустится ниже этого показателя, VPA его удалит и создаст меньший.
  • Верхняя граница (Upper Bound): определяет верхнюю границу для изменения размера. Если использование пода превышает это значение, VPA удалит его и увеличит.
  • Неограниченная цель (Uncapped Target): здесь определяется целевое использование в случае, если вы не задали верхнюю или нижнюю границы для VPA.

Теперь давайте запустим это и посмотрим, что произойдет, если установить updateMode на Auto. Запустим следующее:


$ cat <<EOF | kubectl apply -f -
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
 name: nginx-vpa
spec:
 targetRef:
  apiVersion: "apps/v1"
   kind:       Deployment
   name:       nginx
 updatePolicy:
   updateMode: "Auto"
 resourcePolicy:
   containerPolicies:
   - containerName: "nginx"
     minAllowed:
       cpu: "250m"
       memory: "100Mi"
     maxAllowed:
       cpu: "2000m"
       memory: "2048Mi"
EOF

И затем заново запустим нагрузочный тест. На другом терминале будем наблюдать за подами и увидим, как они удаляются и воссоздаются.



Заключение


Вертикальное автомасштабирование подов — относительно новая концепция автомасштабирования в рамках Kubernetes. Оно больше всего подходит для stateful-приложений или для профилировки использования ресурсов и рекомендаций. В текущей ситуации не рекомендую использовать его в производственной среде в автоматическом режиме, однако режим рекомендаций полезен для получения аналитических данных.


N.B. более подробно о горизонтальном автомасштабировании подов и работе stateful-приложений в кластере можно узнать с помощью видеокурса Kubernetes Мега.