Хотя я не обладаю большим опытом в разработке программного обеспечения — я специалист по обработке данных — но, конечно, много слышала о контейнерах. Насколько легкие они в сравнении с традиционными виртуальными машинами и как они хороши в обеспечении постоянной безопасной среды для кода.
Однако, когда я попыталась создать Docker с моей собственной моделью, я быстро обнаружила, что его работа интуитивно не так понятна. Использовать Docker совсем не так же просто, как ввести RUN в начале скрипта загрузки EC2. Непредсказуемое поведение возникает часто, и довольно утомительно учиться налаживать новый инструмент.
Все это мотивировало меня на создание этой статьи со всеми фрагментами кода, необходимыми для преобразования модели машинного обучения на Python в Docker-контейнер. Вместе мы пройдем установку всех необходимых pip-пакетов и соберем первый образ.
Дисклеймер: модель, о которой пойдет речь — это единичная работа для конкретного случая, это НЕ веб-сервис с конечными точками API, НЕ распределенные параллельные задания. Если вы будете следовать этому руководству, весь процесс помещения кода в контейнер займет не более 25 минут.
Обязательные требования
- AWS аккаунт
- установленный AWS CLI
- установленный Docker с настроенным пользовательским аккаунтом
- установленный Python 3
Создание Docker-файла 👷🏻♀️
Чтобы поместить код в контейнер, нужно создать 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.
Создаем образ с Dockerfile
Команда docker build создает образ согласно инструкциям, заданным в Dockerfile. Осталось дать образу имя.
docker build -t ${IMAGE_NAME}:${VERSION} .
Убедитесь, что образ существует локально:
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
- 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 загружает образ в частный или облачный реестр.
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming