Warum dauert es ewig, Pandas unter Alpine Linux zu installieren?

93

Ich habe festgestellt, dass die Installation von Pandas und Numpy (Abhängigkeit) in einem Docker-Container unter Verwendung des Basisbetriebssystems Alpine vs. CentOS oder Debian viel länger dauert. Ich habe unten einen kleinen Test erstellt, um den Zeitunterschied zu demonstrieren. Abgesehen von den wenigen Sekunden, die Alpine benötigt, um die Build-Abhängigkeiten für die Installation von Pandas und Numpy zu aktualisieren und herunterzuladen, warum dauert die Datei setup.py etwa 70-mal länger als bei der Installation von Debian?

Gibt es eine Möglichkeit, die Installation mit Alpine als Basis-Image zu beschleunigen, oder gibt es ein anderes Basis-Image von vergleichbarer Größe wie Alpine, das für Pakete wie Pandas und Numpy besser geeignet ist?

Dockerfile.debian

FROM python:3.6.4-slim-jessie

RUN pip install pandas

Erstellen Sie ein Debian-Image mit 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

Erstellen Sie ein alpines Bild mit 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
Moku
quelle
1
.apk jetzt verfügbar, so dass keine Erstellung aus der Quelle erforderlich ist - pkgs.alpinelinux.org/packages?name= * pandas & branch = edge
jtlz2
1
@ jtlz2, Pandas ist am Astrand von Alpine nicht verfügbar. das ist schade ...
fccoelho
@fccoelho Es ist jetzt wieder verfügbar!
jtlz2

Antworten:

63

Debian-basierte Images werden nur python pipzum Installieren von Paketen mit folgendem .whlFormat verwendet:

  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)

Das WHL-Format wurde als schnellere und zuverlässigere Methode zur Installation von Python-Software entwickelt, als jedes Mal aus dem Quellcode neu erstellt zu werden. WHL-Dateien müssen nur an den richtigen Speicherort auf dem zu installierenden Zielsystem verschoben werden, während für eine Quelldistribution vor der Installation ein Erstellungsschritt erforderlich ist.

Radpakete pandasund numpywerden in Bildern, die auf der Alpine-Plattform basieren, nicht unterstützt. Wenn wir sie python pipwährend des Erstellungsprozesses mit installieren , kompilieren wir sie daher immer aus den Quelldateien in alpine:

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

und wir können den folgenden inneren Container während der Bilderstellung sehen:

/ # 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

Wenn wir Dockerfileein wenig ändern :

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

Wir erhalten den folgenden Fehler:

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

Leider besteht die einzige Möglichkeit zur Installation pandasauf einem Alpine-Image darin, zu warten, bis der Build abgeschlossen ist.

Wenn Sie das Alpine-Image pandasbeispielsweise in CI verwenden möchten , können Sie es am besten einmal kompilieren, in eine beliebige Registrierung verschieben und als Basis-Image für Ihre Anforderungen verwenden.

BEARBEITEN: Wenn Sie das Alpenbild mit verwenden möchten, pandaskönnen Sie mein Docking- Bild von Nickgryg / Alpine-Pandas ziehen . Es ist ein Python-Image, das pandasauf der Alpine-Plattform vorkompiliert wurde . Es sollte Ihre Zeit sparen.

Nickgryg
quelle
3
Nun, das ist schade. Es sieht jedoch so aus, als würden six, pytz und python-dateutil .whl-Pakete auf Alpine herunterladen. Bedeutet das, dass es möglich ist, Räder für Pandas und Numpy für Alpine zu bauen, aber dass dies derzeit einfach nicht geschieht?
Moku
Nein, es ist nicht möglich, Räder für pandasund nampyauf alpinen Plattformen zu bauen . Diese Räder unterstützen es nicht. Ich habe das in der Antwort gezeigt, als versucht wurde, pandasvon seinem Radpaket in alpines Bild zu installieren .
Nickgryg
@Nickolay Gibt es eine Abhilfe Weg , um einen recyceln pandasBuild, wird auf gebaut worden alpineund dann zwischengespeichert? (Dies könnte irgendwo vor Ort gehostet werden)
jtlz2
2
Der Grund dafür ist, dass diese Räder Binärdateien enthalten, die aus c / c ++ erstellt und mit glibc verknüpft sind. Alpine verfügt jedoch nicht über glibc, sondern verwendet musl. Dies bedeutet, dass neue Binärdateien kompiliert und mit musl verknüpft werden müssen.
ThisGuyCantEven
33

ANTWORT: AB 25/10/2019 GIBT ES FÜR PYTHON 3 NOCH NICHT!

Hier ist eine vollständig funktionierende Docker-Datei:

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

Der Build so:libpython3.7m.so.1.0 (missing)reagiert sehr empfindlich auf die genauen Python- und Alpin-Versionsnummern - wenn diese falsch angegeben werden, scheint dies den Fehler von Max Levy zu provozieren -, aber das oben Genannte funktioniert jetzt für mich.

Meine aktualisierte Docker-Datei ist unter https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b verfügbar


[Früheres Update:]

ANTWORT: NICHT!

In jedem Alpine Dockerfile können Sie einfach *

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

Dies liegt daran numpy, scipyund jetzt pandassind alle verfügbar vorgefertigt auf 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

Eine Möglichkeit, ein erneutes Erstellen oder die Verwendung einer Docker-Ebene zu vermeiden, besteht darin, ein vorgefertigtes, natives Alpine Linux / .apk-Paket zu verwenden, z

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

https://github.com/nbgallery/apks

Sie können diese .apks einmal erstellen und verwenden, wo immer Sie möchten.

Dies erspart Ihnen auch, dass Sie alles andere vorher in das Docker-Image backen müssen - dh die Flexibilität, jedes gewünschte Docker-Image vorab zu erstellen.

PS Ich habe einen Dockerfile-Stub unter https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b eingefügt , der ungefähr zeigt, wie das Image erstellt wird. Dazu gehören die wichtigen Schritte (*):

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
quelle
2
Sieht aus wie es vor kurzem entfernt wurde? pkgs.alpinelinux.org/package/edge/testing/x86/py-pandas
jtlz2
1
@ChrisWedgwood Sie arbeiten aktiv daran - siehe github.com/alpinelinux/aports/pull/6330
jtlz2
1
@ ChrisWedgwood Ich arbeite wieder, Puh!
jtlz2
1
@ jtlz2 Ich bin auf 3.7-slim-buster umgestiegen
xristian
9

ACHTUNG
Schauen Sie sich die @ jtlz2-Antwort mit dem neuesten Update an

VERALTET

Also wurden py3-pandas & py3-numpy-Pakete in das Test-Alpin-Repository verschoben, sodass Sie es herunterladen können, indem Sie diese Zeilen in Ihre Docker-Datei einfügen:

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

Hoffe es hilft jemandem!

Alpine Pakete Links:
- py3-pandas
- py3-numpy

Alpine Repositories docken Informationen an .

stefanitsky
quelle
Das hat bei mir funktioniert! Vielen Dank für die aktualisierte Antwort!
Stratus3D
2
In meiner Antwort
behoben
1
@ jtlz2 cool, danke, aber ich bin zum Debian Buster anstatt zu Alpine gewechselt und habe nicht versucht, es erneut mit Alpine zu installieren, aber trotzdem, danke für die Antwort, habe ich auch meine Antwort
korrigiert
Nur um zu beachten, dass py3-pandas für 3.11.x nicht verfügbar ist, befindet es sich zum Zeitpunkt des Schreibens dieses Kommentars nur in der 'Edge'-Version. edit: Offensichtlich heißt es, dass ich im obigen Beitrag diese Referenz früher verpasst habe, sorry.
fauler
5

Ich werde nur einige dieser Antworten in einer Antwort zusammenfassen und ein Detail hinzufügen, das meiner Meinung nach übersehen wurde. Der Grund, warum bestimmte Python-Bibliotheken, insbesondere optimierte Mathematik- und Datenbibliotheken, so lange brauchen, um auf Alpin aufzubauen, liegt darin, dass die Pip-Räder für diese Bibliotheken Binärdateien enthalten, die aus c / c ++ vorkompiliert und mit glibceinem gemeinsamen Satz von c-Standardbibliotheken verknüpft sind . Debian, Fedora, CentOS verwenden alle (normalerweise) glibc, aber Alpine verwendet musl-libcstattdessen , um leicht zu bleiben . Auf einem glibcSystem aufgebaute c / c ++ - Binärdateien funktionieren auf einem System ohne nicht glibcund das Gleiche gilt für musl.

Pip sucht zuerst nach einem Rad mit den richtigen Binärdateien. Wenn es keine findet, versucht es, die Binärdateien aus der c / c ++ - Quelle zu kompilieren und sie mit musl zu verknüpfen. In vielen Fällen funktioniert dies nicht einmal, wenn Sie nicht über die Python-Header verfügen python3-devoder Tools wie diese erstellen make.

Nun, der Silberstreifen, wie andere bereits erwähnt haben, gibt es apkPakete mit den richtigen Binärdateien, die von der Community bereitgestellt werden. Wenn Sie diese verwenden, sparen Sie sich den (manchmal langwierigen) Prozess des Erstellens der Binärdateien.

ThisGuyCantEven
quelle
4

Wirklich ehrliche Ratschläge hier, wechseln Sie zu einem Debian-basierten Image und dann sind alle Ihre Probleme verschwunden.

Alpine für Python-Anwendungen funktioniert nicht gut.

Hier ist ein Beispiel von mir 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

Das python:3.7.6-busterist besser geeignet , in diesem Fall, aber auch Sie brauchen keine zusätzliche Abhängigkeit in dem O.

Folgen Sie einem nützlichen und aktuellen Artikel: https://pythonspeed.com/articles/alpine-docker-python/ :

Verwenden Sie Alpine Linux nicht für Python-Images. Wenn Sie keine massiv langsameren Build-Zeiten, größere Images, mehr Arbeit und das Potenzial für obskure Fehler wünschen, sollten Sie Alpine Linux als Basis-Image vermeiden. Einige Empfehlungen zur Verwendung finden Sie in meinem Artikel zur Auswahl eines guten Basisbilds.

Flávio Henrique
quelle
Sie können die Anzahl der Ebenen in Ihrem Image reduzieren, z. B. RUN pip install <packegeA> && pip install <packageB> usw., anstatt einen Block von RUN-Befehlen zu verwenden.
Dies
0

Das hat bei mir funktioniert:

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" ]

Der größte Teil des Codes hier stammt aus der Antwort von jtlz2 aus demselben Thread und Faylixe aus einem anderen Thread.

Es stellt sich heraus, dass die leichtere Version von Pandas im Alpine-Repository gefunden wird py3-numpy, aber nicht im selben Dateipfad installiert wird, von dem Python die Importe standardmäßig liest. Daher müssen Sie die hinzufügen ENV. Achten Sie auch auf die alpine Version.

Bishwas Mishra
quelle