Perché ci vogliono anni per installare Pandas su Alpine Linux


103

Ho notato che l'installazione di Pandas e Numpy (è dipendenza) in un container Docker utilizzando il sistema operativo di base Alpine rispetto a CentOS o Debian richiede molto più tempo. Ho creato un piccolo test di seguito per dimostrare la differenza di fuso orario. A parte i pochi secondi che Alpine impiega per aggiornare e scaricare le dipendenze di build per installare Pandas e Numpy, perché setup.py impiega circa 70 volte più tempo rispetto all'installazione di Debian?

Esiste un modo per accelerare l'installazione utilizzando Alpine come immagine di base o esiste un'altra immagine di base di dimensioni comparabili a Alpine che è meglio utilizzare per pacchetti come Pandas e Numpy?

Dockerfile.debian

FROM python:3.6.4-slim-jessie

RUN pip install pandas

Crea un'immagine Debian con Pandas e 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

Crea un'immagine alpina con Pandas e 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 ora disponibile, quindi zero necessità di compilare dal sorgente - pkgs.alpinelinux.org/packages?name= * pandas & branch = edge
jtlz2

1
@ jtlz2, pandas non è disponibile sul bordo del ramo di Alpine. che è un peccato ...
fccoelho

@fccoelho È di nuovo disponibile ora!
jtlz2

Risposte:


65

Le immagini basate su Debian vengono utilizzate solo python pipper installare pacchetti con .whlformato:

  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)

Il formato WHL è stato sviluppato come un metodo più rapido e affidabile per installare il software Python rispetto alla ricostruzione ogni volta dal codice sorgente. I file WHL devono solo essere spostati nella posizione corretta sul sistema di destinazione per essere installati, mentre una distribuzione di origine richiede una fase di compilazione prima dell'installazione.

I pacchetti ruote pandase numpynon sono supportati nelle immagini basate sulla piattaforma Alpine. Ecco perché quando li installiamo utilizzando python pipdurante il processo di costruzione, li compiliamo sempre dai file sorgente in alpine:

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

e possiamo vedere il seguente contenitore interno durante la creazione dell'immagine:

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

Se modifichiamo Dockerfileun po ':

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

otteniamo il seguente errore:

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

Sfortunatamente, l'unico modo per eseguire l'installazione pandassu un'immagine Alpine è attendere il termine della compilazione.

Naturalmente, se si desidera utilizzare l'immagine Alpine con pandasin CI, ad esempio, il modo migliore per farlo è compilarlo una volta, inviarlo a qualsiasi registro e usarlo come immagine di base per le proprie esigenze.

EDIT: Se vuoi usare l'immagine Alpine con pandaspuoi estrarre la mia immagine docker nickgryg / alpine-pandas . È un'immagine Python precompilata pandassulla piattaforma Alpine. Dovrebbe farti risparmiare tempo.


3
Beh, è ​​un peccato. Tuttavia, sembra che six, pytz e python-dateutil stiano scaricando pacchetti .whl su Alpine. Ciò significa che è possibile costruire ruote per panda e numpy per Alpine, ma che al momento non sta accadendo?
moku

No, non è possibile costruire ruote per pandase nampysu piattaforma alpina. Quelle ruote non lo supportano. L'ho mostrato nella risposta, quando ho provato a installarlo pandasdal suo pacchetto di ruote nell'immagine alpina.
nickgryg

@ Nickolay Esiste un modo alternativo per riciclare una pandasbuild che è stata costruita alpinee poi memorizzata nella cache? (questo potrebbe essere ospitato da qualche parte localmente)
jtlz2

2
Il motivo per cui è così è perché queste ruote contengono binari compilati da c / c ++ e collegati con glibc, ma alpine non ha glibc, utilizza invece musl, il che significa che i nuovi binari devono essere compilati e collegati a musl.
ThisGuyCantEven

36

RISPOSTA: DAL 9/03/2020, PER PYTHON 3, ANCORA NON LO FA!

Ecco un Dockerfile funzionante completo:

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

La build è molto sensibile agli esatti numeri di versione di python e alpine - sbagliare sembra provocare l'errore di Max Levy so:libpython3.7m.so.1.0 (missing)- ma quanto sopra ora funziona per me.

Il mio Dockerfile aggiornato è disponibile su https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b


[Aggiornamento precedente:]

RISPOSTA: NON LO FA!

In qualsiasi Dockerfile alpino puoi semplicemente fare *

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

Questo perché numpy, scipye ora pandassono tutti disponibili precostruiti su 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

Un modo per evitare la ricostruzione ogni volta o l'utilizzo di un livello Docker è utilizzare un .apkpacchetto Linux / Alpine nativo precostruito , ad es.

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

https://github.com/nbgallery/apks

Puoi .apkcrearli una volta e usarli ovunque nel tuo Dockerfile ti piaccia :)

Ciò ti evita anche di dover inserire tutto il resto nell'immagine Docker prima del fatto, ovvero la flessibilità di pre-costruire qualsiasi immagine Docker che ti piace.

PS Ho messo uno stub Dockerfile su https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b che mostra approssimativamente come costruire l'immagine. Questi includono i passaggi importanti (*):

RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories
RUN apk update
RUN apk add --update --no-cache libgfortran

2
Sembra che sia stato rimosso di recente? pkgs.alpinelinux.org/package/edge/testing/x86/py-pandas
jtlz2

1
@ChrisWedgwood Ci stanno lavorando attivamente - vedi github.com/alpinelinux/aports/pull/6330
jtlz2

1
@ ChrisWedgwood al lavoro di nuovo, phew!
jtlz2


1
@ jtlz2 Sono passato a 3.7-slim-buster e tutto è andato liscio lì pythonspeed.com/articles/base-image-python-docker-images
xristian

9

ATTENZIONE
Guarda la risposta @ jtlz2 con l' ultimo aggiornamento

Obsoleto

Quindi, i pacchetti py3-pandas e py3-numpy sono stati spostati nel repository alpino di test, quindi puoi scaricarli aggiungendo queste righe al tuo Dockerfile:

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

Spero che aiuti qualcuno!

Collegamenti ai pacchetti alpini:
- py3-pandas
- py3-numpy

Informazioni sui dock di Alpine repository .


Questo ha funzionato per me! Grazie per aver fornito una risposta aggiornata!
Stratus3D

2
Corretto nella mia risposta
jtlz2

1
@ jtlz2 cool, grazie, ma sono passato al debian buster invece di alpine e non ho provato a installarlo di nuovo con alpine, ma comunque, grazie per la risposta, ho anche corretto la mia risposta
stefanitsky

1
Solo per notare che py3-pandas non è disponibile per 3.11.x, è solo nella versione "edge" nel momento in cui scrivo questo commento. edit: Ovviamente si dice che nel post sopra, mi sono perso quel riferimento prima, scusa.
marcio

5

Riunirò solo alcune di queste risposte in un'unica risposta e aggiungerò un dettaglio che penso sia stato perso. Il motivo per cui alcune librerie python, in particolare le librerie matematiche e di dati ottimizzate, impiegano così tanto tempo per essere costruite su alpine è perché le ruote pip per queste librerie includono binari precompilati da c / c ++ e collegati a glibcun insieme comune di librerie standard c. Debian, Fedora, CentOS tutti (tipicamente) usano glibc, ma alpine, per rimanere leggeri, usa musl-libcinvece. I binari c / c ++ compilati su un glibcsistema non funzioneranno su un sistema senza glibce lo stesso vale per musl.

Pip cerca prima una ruota con i binari corretti, se non riesce a trovarne uno, prova a compilare i binari dai sorgenti c / c ++ e li collega a musl. In molti casi, questo non funzionerà nemmeno a meno che tu non abbia gli header Python python3-devo crei strumenti come make.

Ora il lato positivo, come altri hanno detto, ci sono apkpacchetti con i binari appropriati forniti dalla comunità, il loro utilizzo ti farà risparmiare il (a volte lungo) processo di costruzione dei binari.


5

Un consiglio davvero onesto qui, passa all'immagine basata su Debian e poi tutti i tuoi problemi saranno spariti.

Alpine per le applicazioni Python non funziona bene.

Ecco un esempio del mio 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

Il python:3.7.6-buster è più appropriato in questo caso, inoltre, non è necessario alcuna dipendenza in più nel sistema operativo.

Segui un articolo utile e recente: https://pythonspeed.com/articles/alpine-docker-python/ :

Non usare Alpine Linux per immagini Python A meno che tu non voglia tempi di compilazione notevolmente più lenti, immagini più grandi, più lavoro e il potenziale di bug oscuri, ti consigliamo di evitare Alpine Linux come immagine di base. Per alcuni consigli su cosa dovresti usare, consulta il mio articolo sulla scelta di una buona immagine di base.


1
È possibile ridurre il numero di livelli nell'immagine, ad esempio ESEGUI pip install <packegeA> && pip install <packageB> e così via invece di utilizzare un blocco di comandi RUN. Influisce sulle prestazioni della tua build :)
p0l00ck

Puoi anche usarlo pip --no-cacheper radere un po 'più di impronta. Quello che dovresti davvero fare è metterli riga per riga in un requirements.txtfile epip install --no-cache -r requirements.txt
ThisGuyCantEven

1

Questo ha funzionato per me:

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

La maggior parte del codice qui proviene dalla risposta di jtlz2 da questo stesso thread e Faylixe da un altro thread.

Si scopre che la versione più leggera di panda si trova nel repository Alpine py3-numpyma non viene installata nello stesso percorso di file da cui Python legge le importazioni per impostazione predefinita. Pertanto è necessario aggiungere il file ENV. Fai anche attenzione alla versione alpina.


0

pandasè considerato un pacchetto supportato dalla comunità, quindi le risposte a cui puntano edge/testingnon funzioneranno poiché Alpine non supporta ufficialmente i panda come pacchetto principale (funziona ancora, semplicemente non è supportato dagli sviluppatori principali di Alpine).

Prova questo 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

Questo funziona anche per l'immagine Vanilla Alpine, usando FROM alpine:3.12.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.