Kubeflow — фреймворк на базе Kubernetes, который помогает быстро запускать модели машинного обучения. Мы в VK решили внедрить его в свои рабочие процессы и столкнулись с некоторыми трудностями.

Меня зовут Федюнин Андрей, я системный инженер в команде платформы, которая предоставляет разработчикам Kubernetes для запуска приложений, и отвечаю за ML-кластер в нашей команде. Сегодня расскажу, зачем и как мы внедряли Kubeflow, как решали проблемы и к чему пришли.

Эта статья — конспект моего выступления на Cloud Conf. Посмотреть его целиком можно в записи.

Что такое Kubeflow


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



Зачем мы решили внедрять Kubeflow


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

В этом плане Kubeflow и ML cluster помогают тем, что делают ресурсы непривязанными к специалисту. На сервере могут запускаться разные пользователи независимо от того, кому он принадлежит.

Единый инструментарий. У нас в компании много разных проектов и команд, которые работают в Machine Learning. Каждый занимается своей задачей несколько обособленно, обмен знаниями происходит не всегда. Команды используют свои инструменты и подходы при запуске обучения.

Kubeflow решает эту задачу единым набором инструментов и подходов, которые будут использовать все команды. Это позволит сформировать экспертную базу — и если у кого-то возникнут проблемы, внутреннее комьюнити всегда поможет. Кроме того, общие куски кода можно будет переиспользовать

Удешевление GPU. GPU-карточки стоят дорого и доставляются долго. ML cluster позволяет нивелировать эту проблему. Несколько команд могут объединить свои бюджеты для заказа производительных карт и впоследствии совместно полноценно их утилизировать. Также им не нужно ждать, когда карточки поступят и будут установлены. Можно запуститься здесь и сейчас и сразу начать работать, используя свободные ресурсы кластера.

Использование тестовых экземпляров. Когда вендоры предлагают свои тестовые образцы GPU-карточек, они, как правило, дают их на ограниченное время и ограниченным объемом. А многие разработчики хотят протестировать карты в своем окружении, на своем Workload, чтобы получить представление о продукте. Приходится привлекать инженеров ЦОДов, которые физически перетыкают эти карточки из сервера в сервер. Всё это выливается в существенное время простоя карт и дополнительно нагружает инженеров. Совместное использование GPU-карточек с помощью ML сluster решает эту проблему.

Деплой Kubeflow 


Kubeflow предлагает Kustomize в качестве инструмента для деплоя. Kfctl и Kubeflow operator я не беру в расчёт, так как это просто обёртки. Но у нас в команде принято, что мы все системные addon довозим через Helm. Поэтому встал вопрос: как донести этот деплой единообразно со всем остальным? Да и от фишек Helm отказываться не хотелось.

В результате выбор пал на такой инструмент, как Helmfile. Он всеяден: умеет принимать Kustomize-манифесты, Helm-чарты, Kubernetes-манифесты. Ещё теперь мы можем патчить апстримные чарты и добавлять в них отсутствующие ресурсы. Инструмент не идеальный, проблемы есть, но когда работа отлажена, деплой происходит просто. Правда, количество патчей получился существенный: для деплоя Kubeflow их получилось около 100, не считая новых ресурсов, которые мы в итоге добавляли.

Образы


Наш кластер лишён доступа в интернет. Соответственно, все образы, необходимые для деплоя, нужно было загрузить в локальное Registry и поменять всё необходимое в манифестах. Задача несложная, но есть проблема. Kubeflow — это набор операторов, которые сами порождают ресурсы. И в порождаемых ресурсах тоже необходимо заменить образы на наши локальные. Разработчики Kubeflow не всегда предусматривают такую кастомизацию — имя образа они часто зашивают в сам код. С каждым релизом таких вшитых имен всё меньше, но они есть.

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

Сетевые политики


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

Двухфакторная аутентификация


Опять же, по требованиям ИБ нам необходима была двухфакторная аутентификация для доступа к веб-интерфейсу. Kubeflow для аутентификации предлагает OpenID Connect как протокол и dex как IdP (identity provider). Но dex не поддерживает двухфакторную аутентификацию, поэтому такой вариант отпадает. У нас в компании уже был IdP, который поддерживает два фактора, но он не умел работать по протоколу OpenID Connect.

Пришлось привлекать разработчиков нашего решения — они оперативно откликнулись на просьбу и добавили недостающую функциональность. В итоге я убрал dex как компонент аутентификации, и теперь Kubeflow ходит непосредственно в наш Identity-провайдер напрямую. 

Contributors


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

По дефолту Kubeflow для контрибьютора добавляет роль edit, которая позволяет ему делать всё, что угодно, в чужом неймспейсе. Мы изменили это поведение и добавляем роль view как наиболее подходящую. В нашем деплое контрибьюторы имеют гораздо меньше прав: мы упразднили некоторые разрешения, например просмотр секретов, Exec в поды, убрали возможность доступа к чужому Jupyter Notebook. 

Железные настройки


Изменения пришлось вносить не только в софт, но и в железо, в его сетевую часть. Запуск обучения в Kubeflow — это, как правило, stateless-обучение. Все дата-сеты должны быть загружены по сети, все артефакты и логи тоже должны быть выгружены в сетевое хранилище. 

Мы поняли, что текущая сетевая архитектура нас не устраивает и мы не можем с нужной скоростью подвозить данные к картам. Поэтому совместно с сетевыми инженерами мы изменили архитектуру сети с уклоном на горизонтальный трафик и поменяли все сетевые карты. Это позволило на каждой ноде загружать данные со скоростью 50–100 гигабит в секунду. 

Scheduler


Еще мы столкнулись с неоптимальным поведением планировщика Kubernetes. По дефолту он равномерно распределяет нагрузку между всеми нодами кластера. С точки зрения CPU и RAM это нормально, но для GPU нужно иное. Для примера рассмотрим схему:



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

Мы поменяли дефолтное поведение планировщика. Теперь он сначала полностью утилизирует одну ноду и только после этого начинает заселять остальные (Bin Packing). В итоге все пользователи могут спокойно запустить своё обучение на всех доступных карточках. 

Чтобы повысить утилизацию ресурсов, мы рассматриваем возможность замены штатного шедулера на альтернативные решения, например Apache YuniKorn.

Чего нам не хватило в Kubeflow


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

Эта функциональность была реализована с помощью иерархических неймспейсов (HNC) и Shell-Operator. В итоге создаётся общий namespace на команду, в который загружаются все необходимые ресурсы для всех членов. Затем Shell-Operator линкует namespace пользователя с namespace команды. И дальше контроллер иерархических неймспейсов распространяет всю необходимую информацию в неймспейсы пользователей, чтобы они получили все необходимые разрешения.


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



Есть два типа пулов:

  • приватный пул, который отдан эксклюзивно команде — никакие другие команды не могут в нём запускаться;
  • общедоступный пул, серверы в нём могут использовать любые члены команды и пользователи в Kubeflow. 

Для реализации этого подхода мы написали Mutation Webhook. От namespace команды наследуется специальная аннотация в неймспейс пользователя. По этой аннотации Webhook добавляет в поды необходимые nodeAffinity.
 
Удобства для пользователей. Для некоторых внешних сервисов доступ сделали более удобным: разработчик указывает один лейбл и сразу получает сетевой доступ, учётные данные для доступа к сервису и его Endpoint. Это было сделано через ресурс PodDefault и небольшую автоматизацию в Shell-Operator.

Также мы реализовали донос изменений кода в под. Написали Mutation Webhook, который на основании аннотации пода добавлял init-контейнер, в котором клонируется репозиторий. В результате у разработчиков сильно сокращается длительность проведения эксперимента. Им не нужно на каждую строчку кода пересобирать образ — достаточно перезапустить под, и новое изменение уже там.

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

Команда VK Cloud развивает Cloud ML Platform на базе Open-Source-компонентов. В ней мы используем MLflow — в отдельной статье Александр Волынский, технический менеджер ML Platform, рассказывает, почему именно. Вы можете протестировать Cloud ML Platform — для этого мы начисляем новым пользователям 3000 бонусных рублей.

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