Как настроить контейнеры для конвейеров MLOps

Эта запись в блоге посвящена проблеме, с которой недавно столкнулась моя команда при работе над gcloud beta ai и docker зависимыми задачами в рамках проекта MLOps. Такие задачи заключаются в разработке легковесных интеграционных тестов для заказных обучающих приложений. Мы используем унифицированную платформу машинного обучения Google Cloud Vertex AI, поэтому мы можем использовать gcloud beta ai custom-jobs local-run для локального тестирования как на машинах разработки, так и на ранних этапах конвейера CI/CD.

Инженеры по машинному обучению, работающие над пользовательскими обучающими приложениями, успешно провели тесты в своих средах разработки, где доступны Cloud SDK и демон Docker. После того, как локальная разработка была завершена, пришло время настроить среду непрерывной интеграции, которая работает в GitLab.

Настройка образа докера

Как указано в документации, gcloud beta ai custom-jobs local-run код обучения упаковывается в образ Docker и выполняется локально. Под капотом он, кажется, вызывает docker build и docker run, поэтому нашим первым действием было узнать о запуске команд Docker в контейнерах GitLab CI (наши бегуны используют Docker executor). К счастью, GitLab предоставляет обширную документацию по нему!

Если вы читаете документацию GitLab, то заметите, что в большинстве примеров используются приведенные ниже настройки image и services:

Это должно подойти для различных вариантов использования Docker в Docker (он же DinD), но не для нашего. Нам нужен не только демон Docker, но и Cloud SDK в контейнере CI.

Поэтому мы решили собрать собственный образ, начиная с docker:19.03.12 и установив в него Cloud SDK следующим образом.

Несколько вещей, которые нужно иметь в виду:

  1. Образ docker:19.03.12 создан на основе alpine:3.12, поэтому мы использовали подход Alpine для установки Cloud SDK в контейнер, взяв за основу официальный файл Cloud SDK Alpine Dockerfile.
  2. Образ Alpine в Cloud SDK основан на alpine:3.13, поэтому мы не ожидаем проблем с совместимостью при использовании тех же команд поверх docker:19.03.12 / alpine:3.12.
  3. Образ Alpine из Cloud SDK не содержит дополнительных компонентов, и нам нужен gcloud beta. Итак, мы установили компонент, как вы можете видеть в строке 28 вышеприведенного Dockerfile.

Демо

Я собрал репозиторий git, чтобы продемонстрировать пользовательский образ в действии: gitlab.com/ricardomendes/docker-cloud-sdk-sample-repo.

Файл .gitlab-ci.yml, содержащий короткий конвейер CI, состоит из двух шагов. Во-первых, он создает и отправляет пользовательский образ Docker в реестр контейнеров репозитория. Затем он извлекает изображение и запускает несколько команд, которые позволяют нам убедиться, что gcloud beta и docker запущены и работают, как показано в приведенном ниже фрагменте кода:

Результаты:

$ gcloud --version
Google Cloud SDK 361.0.0
beta 2021.10.15
bq 2.0.71
core 2021.10.15
gsutil 5.4
$ docker --version
Docker version 19.03.12, build 48a66213fe
$ docker run hello-world
Unable to find image ‘hello-world:latest’ locally
latest: Pulling from library/hello-world
...
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the “hello-world” image from the Docker Hub. (amd64)
3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal.

Полный журнал сборки доступен здесь.

Вот как мы настраиваем образ с необходимыми службами для запуска gcloud beta ai custom-jobs local-run и запускаем интеграционные тесты в конвейере MLOps, над которым мы работаем.

Заключительные соображения

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

Хотя пользовательское изображение содержит элементарные ресурсы Python 3, необходимые для gcloud, мы поняли, что запускать тесты на основе Python нецелесообразно. Установка зависимостей Python в контейнеры на основе Alpine обременительна (пожалуйста, просмотрите эти ссылки, чтобы понять, что я имею в виду: pythonspeed.com/articles/alpine-docker-python и python.org/dev/peps/pep-0656) , поэтому мы также рассмотрели подход, основанный на Debian, а не на Alpine. Для этого мы начали с google/cloud-sdk:361.0.0, основанного на debian:buster-slim, а затем попытались установить в него Docker, но пока безуспешно.

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

Я надеюсь, что это поможет, и отзывы всегда приветствуются!

Лучший,