Как лучше использовать кеш для установок pip - PullRequest
1 голос
/ 11 октября 2019

Часто я создаю Dockerfile для установки одного программного обеспечения с чем-то вроде pip3 install apache-airflow.

Когда это программное обеспечение является сложным, оно будет иметь несколько десятков пакетов Python, от которых зависит. Например, приведенная выше строка предлагает pip собрать ~ 20 зависимых пакетов. Каждый из этих пакетов также будет иметь свои собственные зависимости, поэтому в итоге я смогу установить 100 или более пакетов Python для установки. Это нормально, если разработчикам требуются эти зависимости, я ничего не могу с этим поделать.

Однако, иногда этот процесс прерывается, потому что не установлена ​​какая-либо обязательная для Linux программа 1007 *, такая как gcc,до звонка на pip. На минимальных дистрибутивах с нестандартными пакетами, такими как Alpine, это становится еще хуже. Я получу такие ситуации:

  • Запрос на установку одной программы (например, airflow)
  • Pip предлагает список из ~ 100 обязательных пакетов Python
  • Загружает их все
  • Начинает установку один за другим
  • Пакет 71/100 выдает ошибку компилятора и все терпит неудачу

Затем я должен вернуться, попытаться добавитьнекоторые альпийские пакеты, которые позаботятся об ошибке компилятора и попробуют еще раз (чтобы увидеть, не сработает ли сейчас пакет 74 из-за другой ошибки компилятора). Однако каждая такая пробная версия занимает очень много времени, поскольку docker build перезагружает все необходимые компоненты и переустанавливает первые ~ 70 пакетов, которые не дают ошибок. Кэш сборки Docker также не используется: технически весь этот длительный процесс представляет собой одну команду, поэтому он создает только одно кэшированное изображение и только в случае успеха. Кроме того, добавление RUN apk get перед pip3 install приводит к тому, что все это создается заново с нуля.

Учитывая, что, например, проблема с пакетом # 71, нет смысла тратить впустуюмного минут, перезагружая все 100 пакетов и перестраивая первые 70, когда я устраняю неполадки моего DockerfileКак я могу более эффективно использовать кеш в такой ситуации?

Мое текущее «решение» - вручную выполнить вывод pip install, скомпилировать список всех зависимостей, которые он получает, и затем преобразовать их вотдельные RUN pip3 install PACKAGE_NAME команды в моем Dockerfile. Таким образом, каждая попытка установки пакета кэшируется отдельно. Однако это не похоже на хорошее использование синтаксиса Dockerfile. Есть ли лучший способ?

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Вот три предложения. Важной частью здесь является то, что вам не нужно доводить его до совершенства с первого раза;поэтому разбейте проблему на более мелкие части и поэкспериментируйте.

Первое общее полезное предложение - разбить ваши RUN утверждения во время разработки. Типичный стиль Docker состоит в том, чтобы иметь небольшое количество больших RUN утверждений

RUN apk add ... \
 && pip3 install -r requirements.txt \
 && ... \
 && apk del ...

Но пока вы разрабатываете это и пытаетесь решить проблемы, может быть полезно разбить это на более мелкие утверждения

RUN apk add ...
# If the next line breaks, you'll get caching on the previous line
RUN pip3 install -r requirements.txt

Отладьте это и объедините их позже.

Во время выполнения docker build после каждого шага будут выводиться строки, подобные

 ---> e38ccc1e7f56

Каждая из этих строкявляется действительным идентификатором образа Docker, и вы можете запустить

docker run --rm -it e38ccc1e7f56 sh

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

RUN pip3 install -r requirements.txt || true

Это всегда будет «успешным», так что вы получите действительный образ Docker. Это будет в том состоянии, в котором вы пытаетесь отлаживать: установка пакета завершилась неудачно, но все до этого в Dockerfile запустилось, и pip уже загрузил пакеты.

Теперь у вас есть интерактивная оболочкав одноразовом контейнере в результате сломанной сборки. Вы можете довольно свободно экспериментировать здесь. Попробуйте запустить pip3 install еще раз;это лучше? apk add помогает какой-то конкретный пакет разработки или компилятор? Важным третьим трюком здесь является проведение этого эксперимента, когда ваш Dockerfile открыт в текстовом редакторе: у вас, вероятно, уже есть рабочая строка apk add, в которую вы можете легко добавить больше пакетов, поэтому каждый раз, когда вам нужен другой пакет, чтобыpip3 install На шаг впереди, просто добавьте его в свой Dockerfile.

Ваша мысль о pip3 install упаковках по одному также находится в этом ключе. Это оптимальное производство Dockerfile? Нет, но вам будет намного легче отлаживать, почему не устанавливается отдельный пакет.

Как только у вас все заработает, вы должны удалить лишние || true биты, объединить ваши строки RUN вместе, и так далее. Думайте об этом как об окончательном этапе очистки перед тем, как вы будете готовы к отправке.


Более новый Docker имеет механизм альтернативной сборки не по умолчанию , который поддерживает некоторый экспериментальный синтаксис сборки. У него есть определенный вариант RUN, явно поддерживающий каталоги кеша , и вы можете использовать его для кэширования каталога .pip. Я не видел много использования этого, отчасти потому, что он так заметно помечен как «экспериментальный».

0 голосов
/ 11 октября 2019

Кэш встроен в pip, я думаю, что кеш хранится где-то в домашнем каталоге пользователя. Я делаю некоторые предположения здесь, но кажется, что этот кэш не используется, потому что вы каждый раз запускаете из нового контейнера докера. Если бы вы могли открыть оболочку в контейнере, вы могли бы экспериментировать с установкой пакетов, пока вы не удовлетворите все необходимые зависимости, и кеш должен быть использован. После того, как вы определили все необходимые пакеты для полной установки, вы должны быть полностью настроены.

Вот еще немного информации о кеше для pip:

https://pip.pypa.io/en/stable/reference/pip_install/#caching

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

https://pip.pypa.io/en/stable/reference/pip_freeze/

По сути, как только вы убедились, что ваши зависимости выполнены, и у вас есть рабочая среда, вы можете использовать pip freeze для созданияrequirements.txt, который можно использовать для создания точно такого же набора установленных пакетов. Это означает, что ваша установка будет детерминированной, поскольку каждый раз будут устанавливаться одни и те же версии.

$ env1/bin/pip freeze > requirements.txt
$ env2/bin/pip install -r requirements.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...