Хотя я не обладаю большим опытом в разработке программного обеспечения — я специалист по обработке данных — но, конечно, много слышала о контейнерах. Насколько легкие они в сравнении с традиционными виртуальными машинами и как они хороши в обеспечении постоянной безопасной среды для кода.
Однако, когда я попыталась создать Docker с моей собственной моделью, я быстро обнаружила, что его работа интуитивно не так понятна. Использовать Docker совсем не так же просто, как ввести RUN
в начале скрипта загрузки EC2. Непредсказуемое поведение возникает часто, и довольно утомительно учиться налаживать новый инструмент.
Все это мотивировало меня на создание этой статьи со всеми фрагментами кода, необходимыми для преобразования модели машинного обучения на Python в Docker-контейнер. Вместе мы пройдем установку всех необходимых pip-пакетов и соберем первый образ.
Дисклеймер: модель, о которой пойдет речь — это единичная работа для конкретного случая, это НЕ веб-сервис с конечными точками API, НЕ распределенные параллельные задания. Если вы будете следовать этому руководству, весь процесс помещения кода в контейнер займет не более 25 минут.
Чтобы поместить код в контейнер, нужно создать Dockerfile
, который расскажет Docker, что нужно вашему приложению.
Минимальный Dockerfile для приложения Python:
FROM python:3.6-stretch
MAINTAINER Tina Bu <[email protected]>
# устанавливаем параметры сборки
RUN apt-get update && \
apt-get install -y gcc make apt-transport-https ca-certificates build-essential
# проверяем окружение python
RUN python3 --version
RUN pip3 --version
# задаем рабочую директорию для контейнера
WORKDIR /usr/src/<app-name>
# устанавливаем зависимости python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# копируем все файлы из корня проекта в рабочую директорию
COPY src/ /src/
RUN ls -la /src/*
# запускаем приложение Python
CMD ["python3", "/src/main.py"]
В Dockerfile выше я начала с базового образа Python 3.6. С помощью команды apt-get
обновила системные библиотеки и установила make и build. Затем проверила, что версии python и pip актуальны, задала рабочий каталог, скопировала requirements.txt
в контейнер, и pip установил в него все библиотеки. Наконец, я скопировала все файлы с остальным кодом в контейнер, проверила, чтобы все нужные мне файлы были на месте, и запустила файл точки входа main.py
.
Dockerfile
должен работать, если структура каталога кода выглядит так:
- app-name
|-- src
|-- main.py
|-- other_module.py
|-- requirements.txt
|-- Dockerfile
Все, что нужно сделать, — это изменить <app-name>
на имя вашего приложения, и мы готовы собрать образ.
Существует множество рекомендаций, как сделать docker-файл меньше и повысить его эффективность, но большинство из них выходит за рамки этого поста. Тем не менее о нескольких вещах вам стоит помнить:
Используйте Python stretch как базовый образГоворят, что вместо использования универсального образа Ubuntu, стоит использовать официальные базовые образы, например, Alpine Python. Но оказалось, что с ним очень сложно работать, особенно, устанавливать пакеты. Базовый образ Ubuntu ведет себя предсказуемо, но я предлагаю начать с Python 3.6 stretch, официального образа Python, основанного на Debian 9 (он же stretch). Python stretch предоставляется с установленной и обновленной средой Python и pip. Вам остается только разобраться, как его установить, если вы выбрали Ubuntu.
Устанавливайте только то, что вам нужноОчень заманчиво просто скопировать какой-нибудь шаблонный Dockerfile
, особенно, если это ваш первый Docker-проект. Но я рекомендую устанавливать только то, что вам действительно нужно, чтобы контролировать размер образа. Если вы видите целую кучу make
и build
, установленных другими людьми, попробуйте не включать их сразу, сначала проверьте, работает ли ваш контейнер. Меньший размер образа — это быстрое создание и развертывание. (Еще одна причина попробовать мой минимальный шаблон выше!)
Также для сохранения наименьшего размера используйте .dockerignore
, который работает так же, как .gitignore
, и игнорирует файлы, не влияющие на образ.
.git
.gitignore
README.md
LICENSE
Dockerfile*
docker-compose*
data/*
test/*
Добавьте requirements.txt перед копированием кода
Перед копированием исходного кода всегда добавляйте в Dockerfile файл requirements.txt
. Таким образом, каждый раз, когда вы будете менять код и пересобирать контейнер, Docker будет заново использовать кэшированный слой, пока пакеты не установятся, а не исполнять команду pip install
в каждой сборке, даже если нужные пакеты никогда не менялись. Никто не хочет ждать лишнюю минуту просто потому, что вы добавили пустую строку в код.
Если вам интересно узнать больше о Dockerfile
, в Приложении есть короткий справочник по нескольким базовым командам. Переходим к Шагу 2 — создаем контейнер с только что созданным Dockerfile
.
Команда docker build
создает образ согласно инструкциям, заданным в Dockerfile
. Осталось дать образу имя.
Убедитесь, что образ существует локально:
docker imagesТакже можно поставить tag с более понятным именем, вместо использования hash ID.
docker tag ${IMAGE_ID} ${IMAGE_NAME}:${TAG}
# or
docker tag ${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${TAG}
Теперь нужно протестировать образ локально, чтобы убедиться, все ли работает хорошо.
docker run ${IMAGE_NAME}:${TAG}Поздравляю! Вы упаковали модель в контейнер, который может быть запущен в любом месте, где установлен Docker.
Dockerfile
начинается с FROM
— это необходимое условие. Образы создаются слоями, то есть можно использовать другой образ как основу для вашего. Команда FROM
определяет базовый слой и в качестве аргумента берет имя образа. Можно добавить имя пользователя в Docker Cloud и версию образа в форматеusername/imagename:version
.RUN
используется, чтобы собрать образ. Для каждой команды RUN
Docker запускает ее, затем создает новый слой образа. Таким образом, вы можете легко вернуться к предыдущей версии образа. Синтаксис инструкции RUN
заключается в размещении полного текста команды оболочки после RUN
(например, RUN mkdir /user/local/foo
). RUN
автоматически запускается в оболочке /bin/sh
; другую оболочку можно задать так RUN /bin/bash -c 'mkdir /user/local/foo'
.COPY
копирует локальные файлы в контейнер.CMD
определяет команды, которые запускаются в начале работы образа. В отличие от RUN
, он не создает новый слой, а просто запускает команды. В Dockerfile или образе может быть только один CMD
. Если вам нужно запустить несколько команд, лучше, чтобы CMD
запустил скрипт. EXPOSE
создает подсказку для пользователей образа о том, какие порты предоставляют сервисы. Она включена в информацию, которую можно извлечь отсюда docker inspect <container-id>
. Имейте в виду, что команда EXPOSE
не делает порты доступными для хоста! Для этого требуется публикация портов с помощью флага -p при использовании docker run.PUSH
загружает образ в частный или облачный реестр.Перевод статьи Tina Bu: Build a Docker Container with Your Machine Learning Model
Комментарии