Настройка запросов пода и лимитов в Kubernetes
Kubernetes прекрасно справляется с обработкой состояний отказа и планированием подов. Однако на практике планировщик порой не может разместить под. Это происходит, если он затрудняется оценить, какое количество ресурсов ему требуется для успешной работы. Специалисты до сих пор спорят, какой подход к настройке лимитов и запросов является наилучшим. Порой возникает ощущение, что это скорее искусство, чем наука. Об этом — наша статья.
Pod requests
Запросы пода (pod requests) являются основным значением, используемым планировщиком для оптимального размещения пода. В документации Kubernetes указано, что набор узлов, где можно запланировать под, определяется на шаге фильтрации. К примеру, фильтр PodFitsResources осуществляет проверку, достаточно ли на узле ресурсов, необходимых для удовлетворения ресурсных запросов пода.
При этом запросы приложений можно использовать таким образом, чтобы по ним вы смогли оценить, сколько ресурсов в действительности надо приложению, чтобы обеспечить нормальную работу. В результате планировщик сможет реалистично разместить узлы. Если же вы сначала установите запросы с запасом, чтобы обеспечить довольно большой объём ресурсов для каждого пода, вы можете столкнуться с тем, что время планирования существенно увеличится, а некоторые поды так и не будут полностью запланированы, как будто для них не поступало никаких запросов на ресурсы. В данном случае планировщик часто «выдавливает» поды и не может потом их повторно запланировать. Причина — плоскость управления понятия не имеет, какой объём ресурсов понадобится приложению, а ведь это, что ни говори, ключевой компонент алгоритма планирования.
Pod limits
Лимиты пода (pod limits) являются более чётким ограничением для пода. Данное ограничение представляет собой максимальный объём ресурсов, выделенных контейнеру со стороны кластера.
Опять же, если обратиться к документации Kubernetes, мы увидим, что если для контейнера определён лимит памяти в 4 Гб, то kubelet (а также среда выполнения контейнера) введёт лимит принудительно. То есть среда выполнения не позволит контейнеру задействовать больше ресурсов, чем задано в лимите. К примеру, если процесс в контейнере пробует использовать больше допустимого объёма памяти, то ядро системы завершит данный процесс с ошибкой «out of memory».
Контейнер всегда способен задействовать больше ресурсов, чем это определено в запросе на ресурсы, однако он никогда не сможет задействовать больше, чем определено в ограничении. Это значение очень важно, однако его сложно установить правильно.
В идеальной ситуации мы хотели бы, чтобы требования к ресурсам пода менялись на протяжении жизненного цикла процесса и не вмешивались при этом в другие процессы системы — вот цель установления лимитов.
Вряд ли можно конкретно и точно сказать, какие именно значения устанавливать, однако рекомендуется придерживаться ряда правил: 1. Применяя инструмент нагрузочного тестирования, смоделируйте базовый уровень трафика и обеспечьте наблюдение за использованием ресурсов пода (процессора и памяти). 2. Установите запросы пода на произвольно низкое значение -- ограничьте ресурсы приблизительно в пять раз больше значения запросов и обеспечьте наблюдение. Если уровень запросов слишком низок, процесс не сможет начаться, что нередко становится причиной ошибок времени выполнения Go.
Что касается более высоких ограничений ресурсов, то они усложнят планирование, ведь поду требуется целевой узел с необходимым объёмом доступных ресурсов.
Давайте представим, что у нас есть легковесный web-сервер, имеющий высокие ресурсные ограничения, допустим 4 Гб памяти. Скорее всего, данный процесс придётся масштабировать горизонтально, а каждый новый модуль надо будет планировать на узле, где не меньше 4 Гб доступного объёма памяти. Если же данного узла не существует, то кластер обязан ввести новый узел, необходимый для обработки этого пода, а это уже, в свою очередь, займёт некоторое время. Таким образом, чтобы обеспечить плавное и быстрое масштабирование, важно достичь минимальной разницы между лимитами и запросами ресурсов.
По материалам статьи «5 Things We Overlooked When Deploying Our First App on Kubernetes».