Несколько больших нод или много маленьких?

Photo by La-Rel Easter on Unsplash
Photo by La-Rel Easter on Unsplash

Управление Kubernetes-кластером - это не та задача, где есть одно правильное решение на все случаи жизни. Есть много способов оптимизации кластера и главное здесь - это обеспечение стабильной и отказоустойчивой работы приложений.

Как site-reliability и DevOps инженерам вам нужно иметь в виду потребности приложений, которые будут запускаться в кластере, и учитывать различные факторы при его проектировании.

Выбор правильного размера ноды критичен для разработки масштабируемых приложений. Иметь множество маленьких нод или несколько больших - это две крайности. Для кластера, которому нужно всего 24Gb памяти и 12 CPU лучше выбрать 12 машин по 1-CPU/2GB или две по 6-CPU/12GB ?

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

Отказоустойчивость

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

Если у нас есть две больших воркер ноды и одна их них упадет, то мы потеряем половину всех ресурсов кластера. Если вы не предусмотрели 100% запас ресурсов, то это приведет к катастрофе, так как оставшаяся нода не сможет выдержать двойную нагрузку. Наличие множества воркеров снижает эти риски на n. К примеру, если у вас есть 10 нод в кластере и выключится одна, то вы потеряете только 10% от всей мощности кластера.

Победители: множество маленьких нод

Сложность управления

С большим количеством нод вам нужно будет заботиться о большем количестве серверов, их обновлении и обслуживании. Сократив количество нод их проще обслуживать. Как DevOps и SRE вы можете использовать такие инструменты как Ansible или Puppet, чтобы упростить эти процессы за счет автоматизации.

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

Победители: нет

Простота в распределении контейнеров

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

Победители: несколько больших нод

Автоматическое горизонтальное масштабирование нод

Многие облачные провайдеры предоставляют автоматическое горизонтальное масштабирование воркеров Kubernetes. Если у вас большие ноды, то их масштабирование может быть неудобным. Например, если вы добавляете третью ноду к двухнодовому кластеру, вы увеличиваете мощности кластера на огромные 33%, тогда как для 10-нодового кластера добавление одной ноды увеличит доступные ресурсы на 9%.

Победители: множество маленьких нод

Простота в обслуживании

Ноды Kubernetes-кластера не могут работать непрерывно, их нужно будет останавливать для обновления ОС, обновления версии Kubernetes и другого обслуживания. Если у вас несколько воркер нод, то обновить их без остановки приложений сложнее, так же, при отключении одной ноды, нагрузка на другие существенно увеличится и это тоже может привести к простою. Что не обязательно происходит, если у вас множество нод: вы можете обновлять по одной ноде за раз и Kubernetes без труда перенесет ваши приложения на другие свободные ноды.

Победители: множество маленьких нод

Нагрузка на kubelet

Kubelet отвечает за взаимодействие с нижележащим container runtime (движком для контейнеров) для запуска приложений на воркер нодах. Если вы запускаете множество контейнеров на одной ноде, что типично для кластеров с большими нодами, это может перегрузить kubelet, так как ему нужно будет оперировать большим количеством контейнеров.

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

Победители: множество маленьких нод

Нагрузка на систему

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

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

Победители: несколько больших нод

Выбор размера нод

Что ж, выбор зависит от множества факторов, как всегда! Истина где-то посередине и не стоит выбирать ни одну из крайностей.

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

Какой тип приложений вы запускаете?

Вы запускаете микросервисы из множества контейнеров, которые занимают мало места, или несколько монолитов, требующих гигабайты оперативной памяти и целые ядра CPU? Базы данных? Или все вместе?

Можно ли объединить приложения в группы?

Для смешанных окружений, можете ли вы разделить приложения по категориям? Например, если вы запускаете микросервисное приложение, которое работает с БД MySQL, вы разделяете его компоненты на группы приложений и баз данных. Аналогично, если вы запускаете вместе и монолиты и микросервисы, как ELK стек для мониторинга кластера, вы можете разместить его компоненты по разным группам. Для простоты я назвал только три категории, но вы можете создать столько, сколько хотите.

Максимальное количество ресурсов для каждой категории

Если вы можете сгруппировать приложения по категориям, то после этого вам нужно понять сколько максимум ресурсов может потребоваться на одно приложение из каждой категории. Например, если вы запускаете микросервисы, монолиты и БД в кластере, вам нужно взять максимальные затраты на один инстанс БД, микросервис или монолит.

Посчитать количество приложений в каждой категории

Следующий шаг это найти планируемое количество приложений в каждой из категорий. У вас может быть, например, 8 БД MySQL, 200 микросервисов и 9 монолитов. Запишите их. Не перебарщивайте. Kubernetes спроектирован для масштабирования и вы всегда можете использовать автоматическое масштабирование кластера у некоторых провайдеров. Либо, вы можете добавить ноду вручную позже.

Поместите каждую категорию в отдельный пул нод

Лучший способ оптимизировать ноды это создать пул нод под каждую категорию. Большинство Kubernetes кластеров работают с различными пулами нод и разнородные ноды можно подключать к самостоятельно управляемым кластерам.

Заложите отказоустойчивость

Нужно иметь минимум две ноды в каждом пуле для достижения отказоустойчивости. Kubernetes рекомендует максимум 110 контейнеров на ноду. Так же есть ещё системные контейнеры, которые запущены на нодах, так что имейте это ввиду.

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

Подгоните свои ноды под контейнеры для оптимального управления ресурсами

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

Подгоните ваши контейнеры и ноды для лучшего возможного управления ресурсами. Например, если у нас есть 20 контейнеров, лучше всего будет распределить по 4 пода на одну ноду, тогда нам нужно иметь в запасе 20% ресурсов на каждой ноде, вместо 100% как если бы у нас было всего 2 ноды.

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

Учтите нагрузку от самого Kubernetes

Учтите тот факт, что системные компоненты Kubernetes так же будут потреблять какое-то количество CPU и памяти на каждой ноде, поэтому на самом деле вам будет доступно меньше ресурсов, чем есть на ноде. Уточните эти параметры у вашего облачного провайдера и добавьте к ресурсам ноды.

Подводя итог

Учитывая все вышесказанное, вам нужно сделать следующее, чтобы найти оптимальные значения:

Количество контейнеров на ноде = Корень квадратный из количества контейнеров, округленный до целого в меньшую сторону, при условии, что количество контейнеров на ноду не превышает рекомендуемое значение

Количество нод = Количество контейнеров/Количество контейнеров на ноду

Запас ресурсов = Количество контейнеров на ноду * Максимальное количество ресурсов на контейнер/(Количество нод - Максимальное допустимое количество отключенных нод)

Ресурсы ноды = максимальное кол-во ресурсов, требуемое контейнеру * кол-во контейнеров на ноде + запас ресурсов + ресурсные требования системных компонент  Kubernetes

Пример

Чтобы понять, как это работает, давайте рассмотрим пример.

Давайте скажем, что нам нужны два пула нод:

  1. Микросервисы - 200 микросервисов с 0.1 CPU и 100MB RAM, требуемых на контейнер.

  2. Базы данных - 20 PostgreSQL баз данных с 2 CPU и 4GB RAM, требуемых на контейнер.

Предположим, что компоненты Kube system будут потреблять 0.5 CPU и 0.5 GB RAM и мы рассчитываем, что только одна нода может быть недоступна за раз.

Для микросервисного пула:

Ближайшее меньший целый квадрат числа = 196

Кол-во контейнеров на ноду = sqrt(196) = 14

Кол-во нод = 200/14 = 14.28 ~ 15

Максимальное допустимое число неработающих нод = 1

Запас ресурсов = 14 * (0.1 core + 100MB RAM)/(15–1) = 0.1 core + 100MB RAM

Ресурсы ноды = (0.1 core + 100MB RAM) * 14 + 0.1 core + 100MB RAM + 0.5 cores + 500MB RAM = 2 core + 2GB RAM

Для пула баз данных:

Ближайшее меньший целый квадрат числа = 16

Кол-во контейнеров на ноду = sqrt(16) = 4

Кол-во нод = 20/4 = 5

Максимальное допустимое число неработающих нод = 1

Запас ресурсов = 4 * (2 core + 4GB RAM)/(5–1) = 2 core + 4GB RAM

Ресурсы ноды = (two core + 4GB RAM) * 4 + 2 core + 4GB RAM + 0.5 cores + 0.5 GB RAM = 10.5 core + 20.5 GB RAM

Следовательно, для микросервисного пула вам будет нужно 15 воркер нод с 2 ядрами и 2 GB RAM каждая, и для пула БД вам нужно будет 5 воркер нод с 10.5 ядрами и 20.5 GB RAM каждая. Для простоты можно округлить числа до ближайшей большей доступной конфигурации машины.

Заключение

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

Комментарии (0)