Почему для установки Pandas на Alpine Linux требуется возраст?

Я заметил, что установка Pandas и Numpy (его зависимость) в контейнере Docker с использованием базовой ОС Alpine vs. 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

Постройте альпийское изображение с помощью 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

На изображениях на основе 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 во время процесса построения, мы всегда скомпилируем их из исходных файлов в альпийском режиме:

  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 на альпийском изображении - дождаться завершения сборки.

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

EDIT: Если вы хотите использовать альпийское изображение с pandas вы можете вытащить изображение докеры nickgryg/alpine-pandas. Это изображение python с предварительно скомпилированными pandas на платформе Alpine. Это должно сэкономить ваше время.

Ответ 2

[Обновление:]

ОТВЕТ: ЭТОГО НЕТ!

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

RUN apk add [email protected] [email protected] [email protected]

Это потому, что 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 - это использовать предварительно собранный, собственный пакет Alpine Linux/.apk, например

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

Ответ 3

ПОСЛЕДНИЕ ОБНОВЛЕНИЯ 17/09/2019

Итак, 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

Hope it helps someone!

Alpine packages links:
- py3-pandas
- py3-numpy

Alpine repositories docks info.

Ответ 4

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

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

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