Полное пошаговое руководство по созданию образа Docker (GPU или CPU) вместе с объяснением всех передовых методов, которым следует следовать, которые будут использоваться для обслуживания любого программного обеспечения на основе машинного обучения.
Создание образа Docker обычно считается тривиальным по сравнению с разработкой других компонентов системы машинного обучения, таких как конвейер данных, обучение модели, обслуживание инфраструктуры и т. Д. Но неэффективный, громоздкий образ докера может значительно снизить производительность и даже может привести к снижению производительности инфраструктуры обслуживания.
0. Отказ от ответственности:
Этот блог направлен на создание идеального образа Docker, а не на его концепцию или преимущества. Я предполагаю, что у вас есть базовые знания по нескольким темам, связанным с Docker:
- Общая работа Docker
- Основы сборки Docker, запуск
- Написание и синтаксис Dockerfile
1. Общие рекомендации по сборке Docker
Существует довольно много очень хороших источников для общих рекомендаций, таких как официальное руководство по докерам, но я хотел бы сохранить это краткое и актуальное для проекта на основе системы машинного обучения.
- Requirements.txt всегда должен иметь версию пакета Python. Никогда не пишите просто имя пакета, так как он всегда будет устанавливать последний пакет и в процессе полностью лишает смысла использование docker.
- Всегда группируйте похожую команду RUN, что приведет к единому слою Docker. (Я избегу соблазна объяснить это, поскольку это немного выходит за рамки)
eg:
RUN apt update && \ apt install --no-install-recommends -y build-essential gcc curl ca-certificates python3 && \ apt clean && rm -rf /var/lib/apt/lists/*
- Используйте флаг ‘- -no-cache-dir’ команды pip, поскольку целевая среда является производственной.
RUN pip install --no-cache-dir --user -r /req.txt
- Используйте .dockerignore, чтобы избежать ненужного контекста сборки. Это работает точно так же, как .gitignore
- По возможности используйте тонкую версию базового образа, например python: buster-slim, debian: buster-slim и т. Д.
- Избегайте использования базового образа Docker на базе Alpine. Это может быть немного спорно, но поверьте мне, они плохо работают с Python. Обратитесь к этому прекрасному блогу Itamar Turner-Trauring.
2. Создание образа Docker для любого проекта Python (ЦП):
В большинстве случаев система машинного обучения будет основана на Python, поэтому очень важно эффективно создавать любой образ Docker на основе Python. Давайте пройдемся по ним.
2.1 Одноступенчатый
- Одноступенчатый будет выполнять все задачи за одно и то же время сборки докера.
- Последовательность действий состоит в том, чтобы выбрать базовый образ, установить пакеты ОС, скопировать исходный код, установить пакеты, установить точку входа (если требуется) или другие команды.
В демонстрационных целях я использую следующие пакеты:
После запуска команды docker build размер образа докера составил 1,64 ГБ.
- Одноэтапный метод очень прост, может работать во многих случаях использования. Это неплохая практика, но у нее есть некоторые фундаментальные недостатки, особенно для проекта на основе Python.
- Здесь использование '- -no-install-рекомендует' в apt и '- -no-cache-dir' в pip является ключевым, как я уже говорил ранее, мы не хотим хранить кеш, поскольку он не предназначен для разработки окружающая среда, но не для производства. Фактически, если вы используете любую платформу CI / CD (например, действие Github) с ограниченным пространством для хранения, она будет работать только с использованием этого метода.
- Библиотека Python не работает из коробки, ее нужно сначала скомпилировать на C. Нам просто нужна скомпилированная часть любой библиотеки, а не все остальные остатки. Как вы можете видеть в одноступенчатом примере выше; при выполнении «pip install» все библиотеки сначала загружаются, а затем компилируются.
- Мы должны удалить (и мы можем использовать команды bash) все промежуточные и оставшиеся компоненты, созданные при установке библиотек. Это доставит много хлопот и может даже сломать библиотеку, если будет сделано неправильно. Это настоящий прорыв, поэтому многие из нас просто избегают этого и внедряют громоздкий образ в производство. Но Docker Multi-stage приходит нам на помощь.
2.2 Многоступенчатая
- Многоступенчатая сборка Docker на сегодняшний день является одним из наиболее эффективных методов оптимизации, при этом их легко читать и поддерживать. Чтобы написать действительно эффективный файл Dockerfile, вам традиционно приходилось использовать уловки оболочки и другую логику, чтобы слои были как можно меньше и чтобы каждый слой имел артефакты, необходимые для предыдущего слоя, и ничего больше.
- При многоступенчатой сборке вы используете несколько операторов
FROM
в своем Dockerfile. КаждаяFROM
инструкция может использовать различную базу, и каждая из них начинает новый этап сборки. Вы можете выборочно копировать артефакты с одного этапа на другой, оставляя все нежелательное в конечном изображении. Чтобы показать, как это работает, см. Пример.
Для сравнения: размер многоступенчатого образа докера составляет 1,61 ГБ, а размер одноступенчатого - 1,64 ГБ. Это улучшение (хотя оно и кажется небольшим), здесь происходит много вещей, что позволяет нам попытаться понять вкратце.
- Строка 1–5 - это 1-й этап или этап компиляции, на котором мы устанавливаем библиотеки Python (которые сначала загружаются, а затем выполняются на языке C, поэтому мы даже установили gcc). Затем мы просто копируем скомпилированные библиотеки со стадии 1 на стадию 2 или стадию выполнения, используя синтаксис
COPY --from=<stage 1> stage1/src stage2/destination
- Но, как видно из скриншота, особых улучшений мы не видим. Мы, безусловно, увидим огромное улучшение в других языках, но у Python есть несколько хитростей,
→ Многие библиотеки теперь поставляются в виде предварительно скомпилированных .whl - это формат колеса из PyPi, который не требует какой-либо компиляции.
→ Значит ли это, что для проекта Python не существует многоэтапной сборки? Абсолютно да !!! Не все пакеты PyPi предварительно скомпилированы в формате .whl, многие из них являются устаревшими tar.gz (сжатыми tarballs), которые необходимо сначала скомпилировать И здесь многоступенчатая сборка сработает.
→ Кроме того, многоэтапность применима, если вы создаете пакет python из исходного кода или используете локальный пакет с помощью setup.py, поскольку, опять же, они должны быть сначала скомпилированы.
→ Я настоятельно рекомендую вам прочитать эту статью из Real Python, в которой объясняется, что такое колеса в Python.
→ Из req.txt, который я использую для демонстрации, только вышеуказанные пакеты не являются форматом колеса, а также они уже очень маленькие по размеру. Но если некоторые пакеты не являются предварительно скомпилированными колесами и имеют большой размер, это приведет к потере большого размера диска.
3. Создание образа Docker для любого проекта Python (GPU):
Создание образа Docker на базе ЦП несложно, но не то же самое, что и создание докера на базе графического процессора. Если не построить должным образом, он может стать огромным. Я сосредоточусь на практической части и части реализации, а не на ее теоретической части (так как я думаю, что это выходит за рамки данной статьи).
3.1 Необходимые условия
- И Tensorflow, и Pytorch используют драйверы графического процессора Nvidia CUDA. Поэтому последние драйверы Nvidia, драйверы CUDA и соответствующие им cuDNN должны быть сначала установлены на хост-машине (я не могу описывать процесс здесь, поскольку он выходит за рамки, возможно, для какого-то другого блога).
- После подготовки хост-устройства необходимо установить nvidia-docker2, что позволит движку Docker получить доступ к базовым драйверам графического процессора Nvidia.
- Наиболее важной частью является выбор правильной версии / тега CUDA, cuDNN для образа докера nvidia и тензорного потока / pytorch по отношению к нему. Таким образом, эта система машинного обучения может использовать базовое оборудование графического процессора. Поверьте мне, это может быть действительно неприятной задачей, поэтому у меня есть практическое правило:
→ Всегда используйте ту же версию CUDA и cuDNN в образе Docker, что и на соответствующем хост-компьютере.
→ Не устанавливайте слепо последнюю версию библиотеки tensorflow / pytorch из PyPi. Совершенно неверно, что любая версия этого пакета будет работать с любой версией CUDA, cuDNN. Фактически, комбинация обеих последних версий, tenorflow / pytorch с CUDA / cuDNN может быть несовместимой. Всегда сначала проверяйте комбинацию в среде разработки.
→ В Docker-хабе Nvidia много образов, поэтому понимание их тегов и выбор правильного образа - самый важный строительный блок. Описание официального докер-хаба Nvidia:
Нас интересует только база, среда выполнения, а не разработка (поскольку мы ориентируемся на среду prod). Как выбрать конкретный тег? Я отвечу на него в следующем подразделе.
3.2 Одноступенчатый
- Выбор тега: практическое правило, которому я следую:
я. Шаг 1. Проверьте версию CUDA и cuDNN базовой хост-машины.
II. Шаг 2. Выберите образ Docker на основе шага 1. Итак, в моем случае я выбрал «nvidia / cuda: 10.1-cudnn7-runtime». Почему время выполнения? Потому что это тот, который включает как CUDA, так и cuDNN.
iii. Шаг 3: Выберите правильную версию tensorflow / pytorch, совместимую с этой версией CUDA и cuDNN. В моем случае это был тензорный поток = 2,20.
iv. Предупреждающий шаг: образ докера от Nvidia может быть более старой версией Ubuntu (18.04 или даже 16.04), которая установит python 3.6. Поэтому здесь необходимо уделить внимание проверке совместимости вашего проекта, а также внешних пакетов с версией python. В любом случае конкретная версия может быть установлена из исходников.
Примечание. Поскольку вы можете видеть, что образ Docker от nvidia основан на ubuntu 18.04, мне нужно сделать небольшую дополнительную настройку, чтобы установить tensorflow = 2.2.0.
3.3 Многоступенчатая
- Мы можем использовать тот же механизм, который я показал в 2.2.
- Первый этап будет использоваться для загрузки и компиляции пакетов Python, а затем они будут скопированы на второй этап или этап выполнения.
- Здесь также должны использоваться все правила большого пальца из 3.2.
Примечание: чтобы сделать python 3.8 по умолчанию, я добавил дополнительный код, если это не ваш случай, вы можете избежать этой проблемы.
- Опять же, незначительное улучшение, но даже здесь логика / объяснение применимы, как и в случае 2.2.
- Я настоятельно рекомендую всегда использовать многоступенчатую сборку в любом сценарии использования, так как это также улучшает читаемость.
4. Проверка образа Docker с помощью Dive
- Даже после создания образа докера с соблюдением всех возможных передовых практик мы все равно должны исследовать какие-либо улучшения.
- Dive - отличный инструмент командной строки, предназначенный для изучения образа докера, содержимого слоя и поиска способов уменьшить размер вашего образа Docker / OCI. Он имеет 24k + звезд на GitHub. Кроме того, им очень легко пользоваться и ориентироваться.
- В нем есть две очень полезных матрицы:
я. Потенциально потраченное впустую пространство
ii. Оценка эффективности изображения
- Но его лучшая особенность - это интеграция с любым инструментом CI. Мы можем установить условие для любой из двух или обеих метрик, и если условие не выполняется, задание CI также не удастся. Таким образом, мы всегда можем быть уверены в образе Docker, созданном для каждого задания CI.
Вывод: основной целью всегда должен быть минимальный размер образа докера, поскольку любая сборка образа докера для системы машинного обучения всегда будет тяжелой. Мы всегда должны следовать всем лучшим практикам, особенно многоступенчатой сборке и управлению версиями пакетов. И последнее, но также самое важное для образов на основе графических процессоров - это проверка конфигурации в среде разработки.
Вы можете связаться со мной через LinkedIn, если потребуется помощь.