Почему установка Pandas на Alpine Linux занимает много времени

103

Я заметил, что установка Pandas и Numpy (это зависимость) в контейнере Docker с использованием базовой ОС Alpine по сравнению с CentOS или Debian занимает гораздо больше времени. Ниже я создал небольшой тест, чтобы продемонстрировать разницу во времени. Помимо нескольких секунд, которые требуется Alpine для обновления и загрузки зависимостей сборки для установки Pandas и Numpy, почему setup.py занимает примерно в 70 раз больше времени, чем установка Debian?

Есть ли способ ускорить установку с использованием Alpine в качестве базового образа или есть другой базовый образ, сопоставимый по размеру с Alpine, который лучше использовать для таких пакетов, как Pandas и Numpy?

Dockerfile.debian

FROM python:3.6.4-slim-jessie

RUN pip install pandas

Создайте образ Debian с помощью Pandas и Numpy:

[PandasDockerTest] time docker build -t debian-pandas -f Dockerfile.debian . --no-cache
    Sending build context to Docker daemon  3.072kB
    Step 1/2 : FROM python:3.6.4-slim-jessie
     ---> 43431c5410f3
    Step 2/2 : RUN pip install pandas
     ---> Running in 2e4c030f8051
    Collecting pandas
      Downloading pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl (26.2MB)
    Collecting numpy>=1.9.0 (from pandas)
      Downloading numpy-1.14.1-cp36-cp36m-manylinux1_x86_64.whl (12.2MB)
    Collecting pytz>=2011k (from pandas)
      Downloading pytz-2018.3-py2.py3-none-any.whl (509kB)
    Collecting python-dateutil>=2 (from pandas)
      Downloading python_dateutil-2.6.1-py2.py3-none-any.whl (194kB)
    Collecting six>=1.5 (from python-dateutil>=2->pandas)
      Downloading six-1.11.0-py2.py3-none-any.whl
    Installing collected packages: numpy, pytz, six, python-dateutil, pandas
    Successfully installed numpy-1.14.1 pandas-0.22.0 python-dateutil-2.6.1 pytz-2018.3 six-1.11.0
    Removing intermediate container 2e4c030f8051
     ---> a71e1c314897
    Successfully built a71e1c314897
    Successfully tagged debian-pandas:latest
    docker build -t debian-pandas -f Dockerfile.debian . --no-cache  0.07s user 0.06s system 0% cpu 13.605 total

Dockerfile.alpine

FROM python:3.6.4-alpine3.7

RUN apk --update add --no-cache g++

RUN pip install pandas

Создайте образ Alpine с помощью Pandas & Numpy:

[PandasDockerTest] time docker build -t alpine-pandas -f Dockerfile.alpine . --no-cache
Sending build context to Docker daemon   16.9kB
Step 1/3 : FROM python:3.6.4-alpine3.7
 ---> 4b00a94b6f26
Step 2/3 : RUN apk --update add --no-cache g++
 ---> Running in 4b0c32551e3f
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
(1/17) Upgrading musl (1.1.18-r2 -> 1.1.18-r3)
(2/17) Installing libgcc (6.4.0-r5)
(3/17) Installing libstdc++ (6.4.0-r5)
(4/17) Installing binutils-libs (2.28-r3)
(5/17) Installing binutils (2.28-r3)
(6/17) Installing gmp (6.1.2-r1)
(7/17) Installing isl (0.18-r0)
(8/17) Installing libgomp (6.4.0-r5)
(9/17) Installing libatomic (6.4.0-r5)
(10/17) Installing pkgconf (1.3.10-r0)
(11/17) Installing mpfr3 (3.1.5-r1)
(12/17) Installing mpc1 (1.0.3-r1)
(13/17) Installing gcc (6.4.0-r5)
(14/17) Installing musl-dev (1.1.18-r3)
(15/17) Installing libc-dev (0.7.1-r0)
(16/17) Installing g++ (6.4.0-r5)
(17/17) Upgrading musl-utils (1.1.18-r2 -> 1.1.18-r3)
Executing busybox-1.27.2-r7.trigger
OK: 184 MiB in 50 packages
Removing intermediate container 4b0c32551e3f
 ---> be26c3bf4e42
Step 3/3 : RUN pip install pandas
 ---> Running in 36f6024e5e2d
Collecting pandas
  Downloading pandas-0.22.0.tar.gz (11.3MB)
Collecting python-dateutil>=2 (from pandas)
  Downloading python_dateutil-2.6.1-py2.py3-none-any.whl (194kB)
Collecting pytz>=2011k (from pandas)
  Downloading pytz-2018.3-py2.py3-none-any.whl (509kB)
Collecting numpy>=1.9.0 (from pandas)
  Downloading numpy-1.14.1.zip (4.9MB)
Collecting six>=1.5 (from python-dateutil>=2->pandas)
  Downloading six-1.11.0-py2.py3-none-any.whl
Building wheels for collected packages: pandas, numpy
  Running setup.py bdist_wheel for pandas: started
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: still running...
  Running setup.py bdist_wheel for pandas: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/e8/ed/46/0596b51014f3cc49259e52dff9824e1c6fe352048a2656fc92
  Running setup.py bdist_wheel for numpy: started
  Running setup.py bdist_wheel for numpy: still running...
  Running setup.py bdist_wheel for numpy: still running...
  Running setup.py bdist_wheel for numpy: still running...
  Running setup.py bdist_wheel for numpy: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/9d/cd/e1/4d418b16ea662e512349ef193ed9d9ff473af715110798c984
Successfully built pandas numpy
Installing collected packages: six, python-dateutil, pytz, numpy, pandas
Successfully installed numpy-1.14.1 pandas-0.22.0 python-dateutil-2.6.1 pytz-2018.3 six-1.11.0
Removing intermediate container 36f6024e5e2d
 ---> a93c59e6a106
Successfully built a93c59e6a106
Successfully tagged alpine-pandas:latest
docker build -t alpine-pandas -f Dockerfile.alpine . --no-cache  0.54s user 0.33s system 0% cpu 16:08.47 total
моку
источник
1
.apk теперь доступен, поэтому сборка из исходного кода не требуется - pkgs.alpinelinux.org/packages?name= * pandas & branch = edge
jtlz2
1
@ jtlz2, pandas недоступен на краю ветки Alpine. а жаль ...
fccoelho 06
@fccoelho Теперь он снова доступен!
jtlz2

Ответы:

65

Образы на основе Debian используются только python pipдля установки пакетов в .whlформате:

  Downloading pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl (26.2MB)
  Downloading numpy-1.14.1-cp36-cp36m-manylinux1_x86_64.whl (12.2MB)

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

Пакеты колес pandasи numpyизображения не поддерживаются на платформе Alpine. Вот почему, когда мы устанавливаем их, используя python pipв процессе сборки, мы всегда компилируем их из исходных файлов в alpine:

  Downloading pandas-0.22.0.tar.gz (11.3MB)
  Downloading numpy-1.14.1.zip (4.9MB)

и мы можем видеть следующий контейнер внутри во время построения образа:

/ # ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 /bin/sh -c pip install pandas
    7 root       0:04 {pip} /usr/local/bin/python /usr/local/bin/pip install pandas
   21 root       0:07 /usr/local/bin/python -c import setuptools, tokenize;__file__='/tmp/pip-build-en29h0ak/pandas/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n
  496 root       0:00 sh
  660 root       0:00 /bin/sh -c gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -DTHREAD_STACK_SIZE=0x100000 -fPIC -Ibuild/src.linux-x86_64-3.6/numpy/core/src/pri
  661 root       0:00 gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -DTHREAD_STACK_SIZE=0x100000 -fPIC -Ibuild/src.linux-x86_64-3.6/numpy/core/src/private -Inump
  662 root       0:00 /usr/libexec/gcc/x86_64-alpine-linux-musl/6.4.0/cc1 -quiet -I build/src.linux-x86_64-3.6/numpy/core/src/private -I numpy/core/include -I build/src.linux-x86_64-3.6/numpy/core/includ
  663 root       0:00 ps aux

Если Dockerfileнемного доработать :

FROM python:3.6.4-alpine3.7
RUN apk add --no-cache g++ wget
RUN wget https://pypi.python.org/packages/da/c6/0936bc5814b429fddb5d6252566fe73a3e40372e6ceaf87de3dec1326f28/pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl
RUN pip install pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl

получаем следующую ошибку:

Step 4/4 : RUN pip install pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl
 ---> Running in 0faea63e2bda
pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl is not a supported wheel on this platform.
The command '/bin/sh -c pip install pandas-0.22.0-cp36-cp36m-manylinux1_x86_64.whl' returned a non-zero code: 1

К сожалению, единственный способ установить pandasна образ Alpine - дождаться завершения сборки.

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

РЕДАКТИРОВАТЬ: Если вы хотите использовать образ Alpine, pandasвы можете вытащить мой образ докера nickgryg / alpine-pandas . Это образ Python, предварительно скомпилированный pandasна платформе Alpine. Это должно сэкономить ваше время.

Nickgryg
источник
3
Что ж, это плохо. Однако похоже, что шесть, pytz и python-dateutil загружают пакеты .whl на Alpine. Означает ли это, что можно создавать колеса для панд и numpy для Alpine, но в настоящее время этого просто не происходит?
moku
Нет, невозможно построить колеса для альпийской платформы pandasи nampyна ней. Эти колеса его не поддерживают. Я показал это в ответе, когда пытался установить pandasпакет со своего колеса в образе alpine.
nickgryg 02
@Nickolay Есть ли обходной способ переработать pandasсборку, которая была создана, alpineа затем кэширована? (это может быть размещено где-нибудь локально)
jtlz2
2
Причина этого в том, что эти колеса содержат двоичные файлы, созданные из c / c ++ и связанные с glibc, но в alpine нет glibc, вместо этого он использует musl, что означает, что новые двоичные файлы должны быть скомпилированы и связаны с musl.
ThisGuyCantEven 02
36

ОТВЕТ: НА 9.03.2020 ДЛЯ PYTHON 3 ЭТО ЕЩЕ НЕТ!

Вот полный рабочий Dockerfile:

FROM python:3.7-alpine
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk add --update --no-cache py3-numpy py3-pandas@testing

Сборка очень чувствительна к точным номерам версий python и alpine - неправильный ввод этих значений, кажется, вызывает ошибку Макса Леви so:libpython3.7m.so.1.0 (missing)- но теперь все вышесказанное работает для меня.

Мой обновленный файл Dockerfile доступен по адресу https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b


[Предыдущее обновление:]

ОТВЕТ: НЕТ!

В любом Dockerfile Alpine вы можете просто *

RUN apk add py2-numpy@community py2-scipy@community py-pandas@edge

Это потому numpy, что scipyи сейчас pandasвсе они доступны предварительно на alpine:

https://pkgs.alpinelinux.org/packages?name=*numpy

https://pkgs.alpinelinux.org/packages?name=*scipy&branch=edge

https://pkgs.alpinelinux.org/packages?name=*pandas&branch=edge

Один из способов избежать повторной сборки каждый раз или использования слоя Docker - использовать предварительно собранный, собственный .apkпакет / пакет Alpine Linux , например

https://github.com/sgerrand/alpine-pkg-py-pandas

https://github.com/nbgallery/apks

Вы можете собрать их .apkодин раз и использовать в любом месте вашего Dockerfile :)

Это также избавляет вас от необходимости заранее запекать все остальное в образ Docker - т.е. гибкость для предварительной сборки любого образа Docker, который вам нравится.

PS Я разместил заглушку Dockerfile по адресу https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b, в которой примерно показано, как создать образ. К ним относятся важные шаги (*):

RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories
RUN apk update
RUN apk add --update --no-cache libgfortran
jtlz2
источник
2
Похоже, его недавно удалили? pkgs.alpinelinux.org/package/edge/testing/x86/py-pandas
jtlz2
1
@ChrisWedgwood Они активно работают над ней - см github.com/alpinelinux/aports/pull/6330
jtlz2
1
@ChrisWedgwood Опять работает, уф!
jtlz2
1
@ jtlz2 Я переключился на 3.7-slim-buster, и там все прошло гладко pythonspeed.com/articles/base-image-python-docker-images
xristian
9

ВНИМАНИЕ
Посмотрите ответ @ jtlz2 с последним обновлением

УСТАРЕЛО

Итак, пакеты py3-pandas и py3-numpy перемещены в тестовый репозиторий alpine, поэтому вы можете загрузить их, добавив эти строки в свой Dockerfile:

RUN echo "http://dl-8.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
  && apk update \
  && apk add py3-numpy py3-pandas

Надеюсь, это кому-то поможет!

Ссылки на пакеты Alpine:
- py3-pandas
- py3-numpy

Информация о доках репозиториев Alpine .

Стефаницкий
источник
Это сработало для меня! Спасибо за обновленный ответ!
Stratus3D
2
Исправлено в моем ответе
jtlz2
1
@ jtlz2 круто, спасибо, но я перешел на debian buster вместо alpine и не пытался снова установить его с помощью alpine, но в любом случае, спасибо за ответ, также исправил мой ответ
stefanitsky
1
Просто обратите внимание, что py3-pandas недоступен для 3.11.x, он есть только в версии 'edge' на момент написания этого комментария. edit: Очевидно, здесь говорится, что в сообщении выше я просто пропустил эту ссылку ранее, извините.
тухлый
5

Я просто собираюсь объединить некоторые из этих ответов в один ответ и добавить деталь, я думаю, что она была упущена. Причина, по которой некоторые библиотеки python, особенно оптимизированные библиотеки математики и данных, так долго строятся на alpine, заключается в том, что конвейеры для этих библиотек включают двоичные файлы, предварительно скомпилированные из c / c ++ и связанные с glibcобщим набором стандартных библиотек c. Debian, Fedora, CentOS все (обычно) используют glibc, но alpine, чтобы оставаться легким, musl-libcвместо этого использует . C / C ++ исполняемых файлов сборка на glibcсистеме не будет работать в системе без glibcи то же самое касается musl.

Pip сначала ищет колесо с правильными двоичными файлами, если не может найти его, он пытается скомпилировать двоичные файлы из источника c / c ++ и связывает их с musl. Во многих случаях это даже не сработает, если у вас нет заголовков Python python3-devили таких инструментов сборки, как make.

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

ThisGuyCantEven
источник
5

Настоящий честный совет: переключитесь на образ на основе Debian, и тогда все ваши проблемы исчезнут.

Alpine для приложений Python работает не очень хорошо.

Вот пример моего dockerfile:

FROM python:3.7.6-buster

RUN pip install pandas==1.0.0
RUN pip install sklearn
RUN pip install Django==3.0.2
RUN pip install cx_Oracle==7.3.0
RUN pip install excel
RUN pip install djangorestframework==3.11.0

В python:3.7.6-busterэтом случае более уместно, кроме того, вам не нужна дополнительная зависимость в ОС.

Следуйте полезной и недавней статье: https://pythonspeed.com/articles/alpine-docker-python/ :

Не используйте Alpine Linux для образов Python. Если вы не хотите значительно более медленное время сборки, большие образы, больше работы и возможность появления неясных ошибок, вам следует избегать использования Alpine Linux в качестве базового образа. Некоторые рекомендации о том, что вам следует использовать, можно найти в моей статье о выборе хорошего базового изображения.

Флавио Энрике
источник
1
Вы можете уменьшить количество слоев в вашем образе, например: RUN pip install <packegeA> && pip install <packageB> и так далее вместо использования блока команд RUN. Это влияет на производительность вашей сборки :)
p0l00ck
Вы также можете использовать, pip --no-cacheчтобы сбрить немного больше следов. Что вам действительно нужно сделать, так это просто поместить их построчно в requirements.txtфайл иpip install --no-cache -r requirements.txt
ThisGuyCantEven
1

Это сработало для меня:

FROM python:3.8-alpine
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
RUN apk add --update --no-cache py3-numpy py3-pandas@testing
ENV PYTHONPATH=/usr/lib/python3.8/site-packages

COPY . /app
WORKDIR /app

RUN pip install -r requirements.txt

EXPOSE 5003 
ENTRYPOINT [ "python" ] 
CMD [ "app.py" ]

Большая часть кода здесь взята из ответа jtlz2 из того же потока и Faylixe из другого потока.

Оказывается, более легкая версия pandas находится в репозитории Alpine, py3-numpyно не устанавливается по тому же пути к файлу, откуда Python по умолчанию считывает импорт. Поэтому вам нужно добавить расширение ENV. Также помните об альпийской версии.

Бишвас Мишра
источник
0

pandasсчитается пакетом, поддерживаемым сообществом, поэтому ответы, указывающие на edge/testingнего, не будут работать, поскольку Alpine официально не поддерживает pandas в качестве основного пакета (он все еще работает, он просто не поддерживается основными разработчиками Alpine).

Попробуйте этот Dockerfile:

FROM python:3.8-alpine
RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \
&& apk add py3-pandas@community

Это работает и с ванильным альпийским изображением, используя FROM alpine:3.12.

Z4-уровень
источник
-1

alpine требует много времени на установку панд, и размер образа тоже огромен. Я попробовал python: 3.8-slim-buster версию базового образа python. Сборка изображения была очень быстрой, а размер изображения был меньше половины по сравнению с изображением докера alpine python

https://github.com/dguyhasnoname/k8s-cluster-checker/blob/master/Dockerfile

Мукунд Шарма
источник