Dlaczego instalacja Pandy w Alpine Linux zajmuje wieki

107

Zauważyłem, że instalacja Pandas i Numpy (to zależność) w kontenerze Docker przy użyciu podstawowego systemu operacyjnego Alpine vs. CentOS lub Debian trwa znacznie dłużej. Stworzyłem mały test poniżej, aby zademonstrować różnicę czasu. Pomijając kilka sekund, jakie Alpine zajmuje aktualizacja i pobranie zależności kompilacji w celu zainstalowania Pandas i Numpy, dlaczego plik setup.py zajmuje około 70 razy więcej czasu niż podczas instalacji Debiana?

Czy istnieje sposób na przyspieszenie instalacji przy użyciu Alpine jako obrazu podstawowego, czy też istnieje inny obraz podstawowy o rozmiarze porównywalnym do Alpine, który jest lepszy w przypadku pakietów takich jak Pandas i Numpy?

Dockerfile.debian

FROM python:3.6.4-slim-jessie

RUN pip install pandas

Zbuduj obraz Debiana za pomocą Pandas i 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

Zbuduj obraz Alpine za pomocą 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
źródło
2
.apk jest już dostępny, więc nie trzeba kompilować ze źródeł - pkgs.alpinelinux.org/packages?name= * pandas & branch = edge
jtlz2
2
@ jtlz2, pandy nie są dostępne na skraju gałęzi Alpine. a szkoda ...
fccoelho
@fccoelho Jest teraz ponownie dostępny!
jtlz2

Odpowiedzi:

67

Obrazy oparte na Debianie służą tylko python pipdo instalowania pakietów w .whlformacie:

  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)

Format WHL został opracowany jako szybsza i bardziej niezawodna metoda instalacji oprogramowania Python niż za każdym razem ponowne budowanie z kodu źródłowego. Pliki WHL muszą być tylko przeniesione do właściwej lokalizacji w systemie docelowym, aby zostały zainstalowane, podczas gdy dystrybucja źródłowa wymaga kroku kompilacji przed instalacją.

Pakiety kół pandasi numpynie są obsługiwane w obrazach opartych na platformie Alpine. Dlatego kiedy instalujemy je używając python pippodczas procesu budowania, zawsze kompilujemy je z plików źródłowych w alpine:

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

i możemy zobaczyć następujący wewnątrz kontenera podczas budowania obrazu:

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

Jeśli trochę zmodyfikujemy 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

otrzymujemy następujący błąd:

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

Niestety jedyny sposób na zainstalowanie pandas na obrazie Alpine jest poczekanie do zakończenia kompilacji.

Oczywiście, jeśli chcesz używać obrazu Alpine z pandas w CI, najlepszym sposobem na to jest skompilowanie go raz, wypchnięcie do dowolnego rejestru i użycie go jako obrazu podstawowego do swoich potrzeb.

EDYCJA: Jeśli chcesz używać obrazu Alpine pandas, możesz pobrać mój obraz dockera nickgryg / alpine-pandas . Jest to obraz Pythona wstępnie skompilowany pandasna platformie Alpine. Powinno to zaoszczędzić czas.

nickgryg
źródło
3
Cóż, szkoda. Jednak wygląda na to, że sześć, pytz i python-dateutil pobierają pakiety .whl na Alpine. Czy to oznacza, że ​​można zbudować koła dla pand i odrętwiałe dla Alpine, ale teraz tak się nie dzieje?
moku
Nie, nie można budować kół do platformy alpejskiej pandasi nampyna niej. Te koła tego nie obsługują. Pokazałem to w odpowiedzi, kiedy próbowałem zainstalować pandasz pakietu kół w obrazie alpejskim.
nickgryg
@Nickolay Czy istnieje sposób obejścia problemu recyklingu pandaskompilacji, która została skompilowana, alpinea następnie zapisana w pamięci podręcznej? (może to być hostowane gdzieś lokalnie)
jtlz2
2
Powodem tego jest to, że te koła zawierają pliki binarne zbudowane z c / c ++ i połączone z glibc, ale alpine nie ma glibc, zamiast tego używa musl, co oznacza, że ​​nowe pliki binarne muszą być skompilowane i połączone z musl.
ThisGuyCantEven
36

ODPOWIEDŹ: NA DZIEŃ 09.03.2020 W PYTHONIE 3 NADAL NIE JEST!

Oto kompletny działający plik 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

Kompilacja jest bardzo wrażliwa na dokładne numery wersji Pythona i alpejskich - błędne ich pomylenie wydaje się powodować błąd Maxa Levy so:libpython3.7m.so.1.0 (missing) - ale powyższe teraz działa dla mnie.

Mój zaktualizowany plik Dockerfile jest dostępny pod adresem https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b


[Wcześniejsza aktualizacja:]

ODPOWIEDŹ: NIE!

W dowolnym pliku Alpine Dockerfile możesz po prostu zrobić *

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

Dzieje się tak numpy, ponieważ scipyi teraz pandaswszystkie są dostępne w wersji prekompilowanej na 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

Jednym ze sposobów uniknięcia przebudowy za każdym razem lub korzystania z warstwy Docker jest użycie wstępnie skompilowanego, natywnego .apkpakietu Alpine Linux / , np.

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

https://github.com/nbgallery/apks

Możesz je zbudować .apkraz i używać ich w dowolnym miejscu w pliku Dockerfile :)

Oszczędza to również konieczności wypalania wszystkiego innego w obrazie Dockera przed faktem - tj. Elastyczności w tworzeniu dowolnego obrazu Dockera, który Ci się podoba.

PS Umieściłem kod Dockerfile na https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b, który z grubsza pokazuje, jak zbudować obraz. Obejmują one ważne kroki (*):

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
źródło
2
Wygląda na to, że został niedawno usunięty? pkgs.alpinelinux.org/package/edge/testing/x86/py-pandas
jtlz2
1
@ChrisWedgwood Aktywnie nad tym pracują - patrz github.com/alpinelinux/aports/pull/6330
jtlz2
1
@ChrisWedgwood Znowu pracuję, uff!
jtlz2
1
@ jtlz2 Przerzuciłem się na 3.7-slim-buster i wszystko poszło gładko tam pythonspeed.com/articles/base-image-python-docker-images
xristian
9

UWAGA
Spójrz na odpowiedź @ jtlz2 w najnowszej aktualizacji

PRZESTARZAŁY

Tak więc pakiety py3-pandas i py3-numpy zostały przeniesione do repozytorium testowania alpine, więc możesz je pobrać, dodając następujące wiersze do pliku Dockerfile:

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

Mam nadzieję, że to komuś pomoże!

Linki do pakietów alpejskich:
- py3-pandas
- py3-numpy

Informacje o dokach repozytoriów Alpine .

Stefanitsky
źródło
To zadziałało dla mnie! Dziękujemy za udzielenie zaktualizowanej odpowiedzi!
Stratus3D
2
Poprawione w mojej odpowiedzi
jtlz2
1
@ jtlz2 super, dzięki, ale przeniosłem się do debian buster zamiast alpine i nie próbowałem go ponownie zainstalować z alpine, ale w każdym razie, dzięki za odpowiedź,
poprawiłem
1
Wystarczy zauważyć, że py3-pandy nie jest dostępne w wersji 3.11.x, jest tylko w wydaniu „edge” w momencie, gdy piszę ten komentarz. edycja: Oczywiście jest napisane, że w poście powyżej, po prostu przegapiłem to odniesienie wcześniej, przepraszam.
zgniły
6

Zamierzam zebrać niektóre z tych odpowiedzi w jednej odpowiedzi i dodać szczegół, który moim zdaniem został pominięty. Powodem, dla którego niektóre biblioteki Pythona, szczególnie zoptymalizowane biblioteki matematyczne i biblioteki danych, trwają tak długo, aby zbudować na alpine, jest to, że koła pip dla tych bibliotek zawierają pliki binarne prekompilowane z c / c ++ i połączone z glibc, wspólny zestaw standardowych bibliotek c. Debian, Fedora, CentOS używają wszystkich (zazwyczaj) glibc, ale alpine, aby zachować lekkość, używa musl-libczamiast tego. Pliki binarne c / c ++ zbudowane w glibcsystemie nie będą działać w systemie bez glibci to samo dotyczy musl.

Pip szuka najpierw koła z poprawnymi plikami binarnymi, jeśli nie może ich znaleźć, próbuje skompilować pliki binarne ze źródła c / c ++ i łączy je z musl. W wielu przypadkach to nawet nie zadziała, chyba że masz nagłówki Pythona z python3-devlub narzędzia do kompilacji, takie jak make.

Teraz dobra passa, jak wspominali inni, istnieją apkpakiety z odpowiednimi plikami binarnymi dostarczonymi przez społeczność, dzięki którym zaoszczędzisz (czasami długotrwałego) procesu budowania plików binarnych.

ThisGuyCantEven
źródło
6

Prawdziwa szczera rada, przełącz się na obraz oparty na Debianie, a wtedy wszystkie problemy znikną.

Alpine dla aplikacji Pythona nie działa dobrze.

Oto przykład mojego 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

Plik python:3.7.6-buster tym przypadku jest bardziej odpowiednie, ponadto nie potrzebujesz żadnych dodatkowych zależności w systemie operacyjnym.

Śledź przydatny i najnowszy artykuł: https://pythonspeed.com/articles/alpine-docker-python/ :

Nie używaj Alpine Linux dla obrazów Python Jeśli nie chcesz znacznie wolniejszego czasu kompilacji, większych obrazów, więcej pracy i potencjału niejasnych błędów, powinieneś unikać Alpine Linux jako obrazu podstawowego. Aby uzyskać zalecenia dotyczące tego, czego powinieneś użyć, zobacz mój artykuł na temat wyboru dobrego obrazu podstawowego.

Flávio Henrique
źródło
2
Możesz zmniejszyć liczbę warstw w obrazie, np. RUN pip install <packegeA> && pip install <packageB> i tak dalej, zamiast używać bloku poleceń RUN. Wpływa to na wydajność kompilacji :)
p0l00ck
1
Możesz także użyć, pip --no-cacheaby zgolić trochę więcej śladu. To, co naprawdę powinieneś zrobić, to po prostu umieścić je wiersz po wierszu w requirements.txtpliku ipip install --no-cache -r requirements.txt
ThisGuyCantEven
1

To zadziałało dla mnie:

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

Większość kodu pochodzi z odpowiedzi jtlz2 z tego samego wątku i Faylixe z innego wątku.

Okazuje się, że lżejsza wersja pand znajduje się w repozytorium Alpine, py3-numpyale nie jest instalowana w tej samej ścieżce pliku, z której Python domyślnie odczytuje import. Dlatego musisz dodać rozszerzenie ENV. Pamiętaj też o wersji alpejskiej.

Bishwas Mishra
źródło
0

pandasjest uważany za pakiet obsługiwany przez społeczność, więc odpowiedzi, na które wskazuje, edge/testingnie będą działać, ponieważ Alpine oficjalnie nie obsługuje pand jako pakietu podstawowego (nadal działa, po prostu nie jest obsługiwany przez głównych programistów Alpine).

Wypróbuj ten plik 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

Działa to również w przypadku obrazu waniliowego Alpine, używając FROM alpine:3.12.

Poziom Z4
źródło
-1

alpine zajmuje dużo czasu, aby zainstalować pandy, a rozmiar obrazu jest również ogromny. Wypróbowałem wersję Python: 3.8-slim-buster obrazu podstawowego Pythona. Tworzenie obrazu było bardzo szybkie, a rozmiar obrazu był mniejszy o połowę w porównaniu do obrazu dockera w języku alpejskim

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

Mukund Sharma
źródło