Обзор

В нашей компании в производстве на постоянной основе находятся сотни моделей машинного обучения (ML) и расчетных скриптов. И наше подразделение Data Engineering поставило задачу сделать какой-нибудь CD/CD-компонент, наиболее подходящий для наших целей:

  1. Большое количество используемых библиотек от проекта к проекту
  2. Различные исполнительные платформы
  3. Гибкое расписание
  4. Уменьшение времени выхода на рынок (TTM)
  5. Масштабируемость и отказоустойчивость

Для достижения наших целей мы выбрали Kubernetes как лучшую систему оркестрации Docker, Airflow как один из быстро развивающихся планировщиков и Jenkins как одну из самых популярных систем непрерывной интеграции с непрерывной доставкой (CI/CD). Для некоторых задач по оптимизации мы также используем частный реестр Docker по вашему выбору (лучше всего, я думаю, Nexus или JFrog). Мы прошли две версии наших систем автоматизации ML. Первый был о контейнеризации всех приложений и сохранении образов для каждой версии каждого приложения. Не обошлось без недостатков:

  1. Объем памяти. Каждый контейнер занимает в среднем около 2 ГБ дискового пространства.
  2. Пора торговать. Нам нужно дополнительное дополнительное время для каждого запуска теста, чтобы перестроить контейнер во время разработки.
  3. Скорость отладки

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

Концепции

Создание DAG, создание модулей во время выполнения и выполнение кода непосредственно из Git.

Преимущество: устранение недостатков предыдущего подхода.

Работают две части системы:

  1. Генерация DAG
  2. выполнение DAG

Обе эти части используют шаблоны Jinja для DAG и для структур pod Kubernetes.

Генерация DAG

Генерация DAG выполняется после каждой фиксации в системе Git с помощью веб-хука. Дженкинс получает веб-перехватчик и запускает конвейер генерации DAG. Этот конвейер использует бесплатную утилиту

https://github.com/SingularBunny/render-jinja-with-yaml

для рендеринга нашего шаблона Jinja и файла конфигурации YAML.

Файлы конфигурации YAML

Эти файлы размещаются в корневом каталоге проекта в Git и описывают систему CI/CD, как следует генерировать DAG и обрабатывать код. Мы разработали две версии конфигурационных файлов: одношаговую и многошаговую.

Пошаговая настройка

Многоэтапная настройка

Шаги могут быть из разных репозиториев. Выполнение каждого шага — это независимый модуль Kubernetes. Ступени могут быть внешними DAG и преобразованы в датчики воздушного потока. На каждом шаге вы можете определить:

  • базовый образ из общедоступного или частного репозитория
  • команда для выполнения
  • репозиторий git, ветка, ревизия с кодом для выполнения
  • секреты kubernetes, карты конфигурации, пользователь, группа, пользователь контейнера синхронизации git, fsgroup, возможности
  • повторные попытки воздушного потока, повторная задержка

j2 шаблон DAG

Шаблон Jinja DAG используется при генерации dag .py. Для некоторых дополнительных функций я рекомендую использовать подход динамической генерации DAG и прочитать статью Создание динамической DAG с использованием Apache Airflow от Энтони Энао.

Большинство частей шаблона являются общими для многих DAG и выглядят как обычный скрипт Python:

Аргументы по умолчанию взяты из конфигурации YAML:

Шаблон Jinja для генерации пода обычно берется из другого файла шаблона:

Макросы Jinja, которые генерируют операторы:

Макросы Jinja, которые генерируют датчики на внешних дагах:

Генерация всех шагов с использованием итерационных циклов и макросов Jinja:

Результирующий скрипт Python из рендеринга этого шаблона вы могли видеть в Приложении 1

выполнение DAG

На этом этапе DAG выполняется Airflow. Каждый оператор создает свой модуль с шаблоном Airfow с Jinja.

шаблон команды генерации пода j2

Это общий шаблон для всех шагов. И каждый шаг выполняет свою собственную команду. Шаблон выглядит как типичная команда kubectl run с флагом --overrides.

Он использует общедоступный контейнер Kunernetes Git-Sync для извлечения кода из репозитория и контейнера из конфигурации для выполнения. Вы можете поискать более продвинутую команду в скрипте Python из Приложения 1, а результат ее рендеринга — в Приложении 2.

Приложение 1. Пример сгенерированного DAG

Приложение 2. Пример отображаемой команды