[Перевод] Рабочие узлы Kubernetes: много маленьких или несколько больших?

qvo_v845n_v0saxkdqv4-chybts.jpeg


При создании кластера Kubernetes могут возникать вопросы: сколько настроить рабочих узлов и какого типа? Что лучше для кластера on-premise: купить несколько мощных серверов или задействовать десяток старых машин в вашем дата-центре? А в облаке лучше взять восемь одноядерных или два четырехъядерных инстанса?

Ответы на эти вопросы — в статье Даниэля Вайбеля, инженера-программиста и преподавателя обучающего проекта Learnk8s в переводе команды Kubernetes aaS от Mail.ru.

Емкость кластера


В целом, кластер Kubernetes можно рассматривать как большой «суперузел». Его общая вычислительная мощность является суммой мощностей всех составляющих узлов.

Существует несколько способов достичь желаемой целевой емкости кластера. Например, нам нужен кластер с общей емкостью 8 процессорных ядер и 32 ГБ оперативной памяти, потому что набор приложений требует такого количества ресурсов. Тогда можно установить два узла по 16 ГБ памяти или четыре узла по 8 ГБ памяти, два четырехъядерных процессора или четыре двухъядерных.

Вот только два возможных способа создания кластера:

4913bec6f7b28bae4ed9f961ce5c646a.png


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

Какой вариант лучше?


Чтобы ответить на этот вопрос, рассмотрим преимущества обоих вариантов. Мы свели их в таблицу.
Обратите внимание, что мы говорим только про рабочие узлы. Выбор количества и размера главных узлов — совершенно другая тема.

Итак, обсудим подробнее каждый пункт из таблицы.

Первый вариант: несколько больших узлов


Самый экстремальный вариант — один рабочий узел на всю емкость кластера. В примере выше это был бы один рабочий узел с 16 ядрами ЦП и 16 ГБ оперативной памяти.

Плюсы


Плюс № 1. Проще управление
Проще управлять несколькими машинами, чем целым парком. Быстрее накатывать обновления и исправления, проще синхронизировать. Количество сбоев в абсолютных цифрах тоже меньше.

Обратите внимание, что все вышесказанное относится к своему железу, своим серверам, а не к облачным инстансам.


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

Маршрутизация трафика и распределение нагрузки между подами в облаке выполняется автоматически: приходящий из интернета трафик направляется на основной балансировщик нагрузки, тот направляет трафик на порт одного из узлов (сервис NodePort выставляет порт в диапазоне 30000–32767 в каждом узле кластера). Правила, установленные kube-proxy, перенаправляют трафик с узла на под. Вот как это выглядит для десяти подов на двух узлах:

xhzmm3jsahvoqhytxlwm3jxgjoe.jpeg


Плюс № 2. Меньше затрат на узел
Мощная машина дороже, но рост цены не обязательно линейный. Другими словами, один десятиядерный сервер с 10 ГБ памяти обычно дешевле, чем десять одноядерных с тем же количеством памяти.

Но обратите внимание, что это правило обычно не работает в облачных сервисах. В текущих схемах ценообразования у всех основных поставщиков облачных услуг цены растут линейно с увеличением емкости.


Таким образом, в облаке обычно нельзя сэкономить на более мощных серверах.

Плюс № 3. Можно запускать ресурсоемкие приложения
Некоторым приложениям необходимы мощные серверы в кластере. Например, если система машинного обучения требует 8 ГБ памяти, вы не сможете запустить ее на узлах по 1 ГБ, а только при наличии хотя бы одного большого рабочего узла.

Минусы


Минус № 1. Много pod’ов на узел
Если одна и та же задача выполняется на меньшем количестве узлов, то на каждом из них, естественно, будет больше pod’ов.

Это может стать проблемой.

Причина в том, что каждый модуль вносит некоторые накладные расходы на среду выполнения контейнера (например, Docker), а также kubelet и cAdvisor.

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

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

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

fad7fcd9c1007d3ddf682feed3aed379.png


В репозитории Kubernetes некоторые жаловались, что узлы скачут между статусами Ready/NotReady, поскольку регулярные проверки kubelet всех контейнеров на узле занимают слишком много времени.
По этой причине Kubernetes рекомендует размещать не более 110 pod’ов на узел. В зависимости от производительности узла вы можете запускать больше подов на узел, но трудно предсказать, возникнут проблемы или все будет работать хорошо. Стоит заранее протестировать работу.

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

Пять реплик можно распределить только на два узла, и если один из них не работает, он сразу выводит из строя несколько реплик.

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

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

Минус № 3. Хуже последствия сбоя
При небольшом количестве узлов каждый сбой несет более серьезные последствия. Например, если у вас всего два узла, и один из них выходит из строя, исчезает сразу половина ваших модулей.

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

Таким образом, чем больше узлов — тем меньше влияние аппаратных сбоев.

Минус № 4. Больше шаги автомасштабирования
В Kubernetes работает система автомасштабирования кластера для облачной инфраструктуры, что позволяет автоматически добавлять или удалять узлы в зависимости от текущих потребностей. С большими узлами автомасштабирование становится более резким и неуклюжим. Например, на двух узлах добавление дополнительного узла увеличит емкость кластера сразу на 50%. И вам придется заплатить за эти ресурсы, даже если они вам не нужны.

Таким образом, если вы планируете использовать автоматическое масштабирование кластера, то чем меньше узлы — тем более гибкое и экономичное масштабирование вы получите.

Теперь рассмотрим преимущества и недостатки большого количества маленьких узлов.

Второй вариант: множество маленьких узлов


Преимущества этого подхода, по сути, вытекают из недостатков противоположного варианта с несколькими крупными узлами.

Плюсы


Плюс № 1. Меньше последствия сбоя
Чем больше узлов, тем меньше pod’ов на каждом узле. Например, если у вас сто модулей на десять узлов, то на каждом узле будет в среднем по десять модулей.

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

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

Плюс № 2. Хорошая репликация
Если узлов достаточно, то планировщик Kubernetes может назначить всем репликам разные узлы. Таким образом, в случае сбоя узла будет затронута всего одна реплика, а приложение останется доступным.

Минусы


Минус № 1. Труднее управление
Большим количеством узлов труднее управлять. Например, каждый узел Kubernetes должен взаимодействовать со всеми остальными, то есть число связей растет квадратично, и все эти связи нужно отслеживать.

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

Растет нагрузка и на базу данных etcd — каждый kubelet и kube-proxy вызывает watcher для etcd (через API), которому etcd должен транслировать обновления объекта.

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

ce0781c0af525f269c4716c572b79ec7.png


Официально Kubernetes поддерживает кластеры с числом узлов до 5000. Однако на практике уже 500 узлов могут вызвать нетривиальные проблемы.

Для управления большим количеством рабочих узлов следует выбирать более производительные главные узлы. Например, kube-up автоматически устанавливает правильный размер VM для главного узла в зависимости от количества рабочих узлов. То есть чем больше рабочих узлов, тем более производительными должны быть главные узлы.

Для решения этих специфических проблем есть специальные разработки, такие как Virtual Kubelet. Эта система позволяет обойти ограничения и строить кластеры с огромным количеством рабочих узлов.

Минус № 2. Больше накладные расходы
На каждом рабочем узле Kubernetes запускает набор системных демонов — к ним относятся среда выполнения контейнера (например, Docker), kube-proxy и kubelet, включая cAdvisor. Все вместе они потребляют определенное фиксированное количество ресурсов.

Если у вас много небольших узлов, доля этих накладных расходов на каждом узле больше. Например, представьте, что все системные демоны одного узла вместе используют 0,1 ядра ЦП и 0,1 ГБ памяти. Если у вас один десятиядерный узел с 10 ГБ памяти, то демоны потребляют 1% емкости кластера. С другой стороны, на десяти одноядерных узлах по 1 ГБ памяти демоны заберут 10% емкости кластера.

Таким образом, чем меньше узлов, тем эффективнее используется инфраструктура.

Минус № 3. Неэффективное использование ресурсов
На маленьких узлах может сложиться ситуация, что оставшиеся фрагменты ресурсов слишком малы, чтобы назначить им какую-то рабочую нагрузку, поэтому они остаются неиспользуемыми.

Например, каждый pod требует 0,75 ГБ памяти. Если у вас десять узлов, и на каждом по 1 ГБ памяти, можно запустить десять pod’ов — в итоге на каждом узле останется 0,25 ГБ неиспользуемой памяти.

Это означает, что 25% памяти всего кластера тратится впустую.

На большом узле с 10 ГБ памяти вы можете запустить 13 таких модулей — и останется всего один неиспользуемый фрагмент 0,25 ГБ.

В этом случае впустую расходуется только 2,5% памяти.

Таким образом, на больших узлах оптимальнее расходуются ресурсы.

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


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

Например, если приложению требуется 10 ГБ памяти, очевиден выбор в пользу больших узлов. А если приложение требует десятикратной репликации для высокой доступности, вряд ли стоит рисковать, размещая реплики всего на двух узлах — в кластере должно быть минимум десять узлов.

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

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

Единого рецепта не существует, а у каждой ситуации свои нюансы, и только продакшн покажет правду.

Перевод подготовлен командой облачной платформы Mail.ru Cloud Solutions.

© Habrahabr.ru