为什么在 Alpine Linux 上安装熊猫需要很长时间

我注意到在 Docker 容器中安装 Panda 和 Numpy (这是依赖关系) ,使用基本的 OS Alpine 和 CentOS 或 Debian 需要更长的时间。我在下面创建了一个小测试来演示时间差。除了 Alpine 更新和下载构建依赖项来安装 Panda 和 Numpy 所需的几秒钟之外,为什么 setup.py 的安装时间是 Debian 的70倍左右呢?

有没有什么方法可以加快安装使用阿尔卑斯山作为基础映像或有另一个基础映像可比较的大小阿尔卑斯山,更好地使用包像熊猫和麻木?

Dockerfile.debian

FROM python:3.6.4-slim-jessie


RUN pip install pandas

用熊猫和笨蛋来建立 Debian 形象:

[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

用熊猫和笨蛋打造阿尔卑斯山的形象:

[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
99702 次浏览

基于 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 文件只需要移动到要安装的目标系统上的正确位置,而源发行版则需要在安装之前进行构建步骤。

车轮包 pandasnumpy是不支持的图像基础上的高山平台。这就是为什么当我们在建造过程中使用 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 的例子,最好的方法是这样做,编译一次,推到任何注册表,并使用它作为一个基础图像为您的需要。

编辑: 如果你想使用与 pandas阿尔卑斯山的形象,你可以拉我的 尼克格里格/高山熊猫码头形象。它是一个在 Alpine 平台上预编译 pandas的 Python 映像。应该能节省你的时间。

答案: 从2020年3月9日起,对于蟒蛇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 和高山版本号非常敏感——这些错误似乎引起了 Max Levy 的错误 so:libpython3.7m.so.1.0 (missing)——但是上面的内容现在对我有用了。

我更新的 Dockerfile 可以在 https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b找到


[早期更新: ]

答案: 没有!

在任何阿尔卑斯 Dockerfile 你可以简单地做 *

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

这是因为 numpyscipy和现在的 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 映像。

另外,我在 https://gist.github.com/jtlz2/b0f4bc07ce2ff04bc193337f2327c13b上放了一个 Dockerfile 存根,大致显示了如何构建映像。这些步骤包括(*) :

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

请注意
查看带有 < strong > 最新更新的@jtlz2答案

过时了

因此,py3-anda & py3-numpy 包被移动到测试高山存储库,所以,您可以通过在 Dockerfile 中添加以下代码行来下载它:

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

希望能帮到别人!

阿尔卑斯山包链接:
- < a href = “ https://pkgs.alpinelinux.org/package? name = * anda & amp; Branch = edge”rel = “ nofollow norefrer”> py3-anda
Py3-numpy

阿尔卑斯山储藏库 码头信息

只是要把这些答案中的一些在一起的答案,并添加一个细节,我认为是错过了。某些 Python 库,尤其是优化的数学和数据库,之所以花费这么长时间构建在 Alpine 上,是因为这些库的管道轮包含了从 c/c + + 预编译并链接到 gnu-libc (glibc)的二进制文件,gnu-libc (glibc)是一组常见的 c 标准库。Debian、 Fedora 和 CentOS 都(通常)使用 glibc,但为了保持轻量级,Alpine 使用 musl-libc。构建在 glibc系统上的 c/c + + 二进制文件在没有 glibc的系统上无法工作,musl也是如此。

Pip 首先寻找带有正确二进制文件的轮子,如果找不到,它会尝试从 c/c + + 源代码中编译二进制文件,并将它们与 musl 链接起来。在许多情况下,除非使用来自 python3-dev的 python 头或构建工具(如 make) ,否则这种方法甚至无法工作。

正如其他人所提到的,现在有一线希望,社区提供了带有适当二进制文件的 apk包,使用这些文件可以节省构建二进制文件的过程(有时是漫长的)。

实际上,您可以从 alpine 上的纯 Python .whl安装,但是,在编写本文时,由于 musl/gnu问题,Manylinux不支持用于 alpine 的二进制发行版。

2022年10月更新

新版本的 python/pip 通过包 musllinux支持 musl,我假设它是 manylinuxmusl映射。尽管如此,仍然没有官方对 CUDA 的“ musl”支持。

真正诚实的建议在这里,切换到 Debian 为基础的形象,然后所有的问题将消失。

对于 python 应用程序,Alpine 不能很好地工作。

下面是我的 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/:

不要在 Python 映像中使用 Alpine Linux 除非您想要大量更慢的构建时间、更大的映像、更多的工作以及隐藏的 bug 的可能性,否则您将避免使用 Alpine Linux 作为基本映像。有关您应该使用什么的一些建议,请参阅我关于选择一个好的基础图像的文章。

这对我很有效:

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和另一个线程的 费利克斯的答案。

原来,较轻版本的熊猫可以在 Alpine 存储库 py3-numpy中找到,但是它没有安装在 Python 默认读取导入的相同文件路径中。因此,您需要添加 ENV。还要注意阿尔卑斯山的版本。

高山需要很多时间安装熊猫和图像的大小也是巨大的。我尝试了 python: 3.8-Slim-buster 版本的 python 基础图像。与高山蟒蛇码头图像相比,图像构建速度快,图像尺寸小于一半

Https://github.com/dguyhasnoname/k8s-cluster-checker/blob/master/dockerfile

pandas被认为是一个社区支持的软件包,所以指向 edge/testing的答案不会起作用,因为阿尔卑斯山没有正式支持熊猫作为核心软件包(它仍然起作用,只是没有得到阿尔卑斯山核心开发者的支持)。

试试这个 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
ENV PYTHONPATH="/usr/lib/python3.8/site-packages"

这也适用于香草阿尔卑斯山图像,使用 FROM alpine:3.12


更新: 感谢@cegprakash 提出如何使用这个设置的问题,因为您还有一个必须在容器内满足的 requirements.txt文件。

我在 Dockerfile 代码片段中添加了一行,以便将 PYTHONPATH变量导出到容器运行时中。如果这样做,那么需求文件中是否包含 pandasnumpy就无关紧要了(只要它们与通过 apk安装的版本相同)。

需要这样做的原因是,apk/usr/lib下安装 py3-pands@community包,但是该位置不在 pip在安装新包之前检查的默认 PYTHONPATH上。如果我们不包括这个步骤来添加它,pippython将不会找到软件包和 pip将尝试下载和安装它在 /usr/local下,这是我们试图避免。

考虑到我们 真的希望确保 pip不会尝试安装 pandas,我建议 没有requirements.txt文件中包含 pandasnumpy,如果你已经使用上述方法安装了 apk。这只是一个小小的额外保证,事情会按计划进行。

在这种情况下,阿尔卑斯山不是改变阿尔卑斯山苗条的最佳解决方案:

来自巨蟒: 3.8.3-阿尔卑斯山

换个说法:

FROM python:3.8.3-slim

在我的情况下,这个问题通过这个小小的改变得以解决。

我已经通过一些额外的更改解决了安装问题:

规定

  • python3.8-alpine迁移到 python3.10-alpine:
docker pull python:3.10-alpine

重要!

我必须迁移,因为当我安装 py3-pandas时,它将包安装为 python3.10,而不是所需的版本 我使用的是 python3.8)。

要查明软件包的库安装在哪里,可以使用以下命令进行检查:

apk info -L py3-pandas
  • python3.9开始就没有安装 backports.zoneinfo软件包(我必须在 要求中添加一个条件来安装版本低于 3.9的软件包)。
backports.zoneinfo==0.2.1;python_version<"3.9"

安装

在进行前面的更改之后,我继续安装 panda,执行以下操作:

  • /etc/apk/repositories(存储库可以根据发行版本的不同而有所不同)添加3个额外的存储库,参考 给你:
for x in $(echo "main community testing"); \
do echo "https://dl-cdn.alpinelinux.org/alpine/edge/${x}" >> /etc/apk/repositories; \
done
  • 验证文件 /etc/apk/repositories的内容:
$ cat /etc/apk/repositories
https://dl-cdn.alpinelinux.org/alpine/v3.16/main
https://dl-cdn.alpinelinux.org/alpine/v3.16/community
https://dl-cdn.alpinelinux.org/alpine/edge/main
https://dl-cdn.alpinelinux.org/alpine/edge/community
https://dl-cdn.alpinelinux.org/alpine/edge/testing
  • 执行安装 pandas(pynum作为 pandas的依赖项自动安装) :
sudo apk update && sudo apk add py3-pandas
  • 设置环境变量:
export PYTHONPATH=/usr/lib/python3.10/site-packages/
  • 验证可以导入的包(在我的案例中,我用 django 测试了它) :
python manage.py shell
import pandas as pd
import numpy as np
technologies =  ['Spark','Pandas','Java','Python', 'PHP']
fee = [25000,20000,15000,15000,18000]
duration = ['5o Days','35 Days',np.nan,'30 Days', '30 Days']
discount = [2000,1000,800,500,800]
columns=['Courses','Fee','Duration','Discount']
df = pd.DataFrame(list(zip(technologies,fee,duration,discount)), columns=columns)
print(df)

下面的 Dockerfile 帮助我安装熊猫,以及下面列出的其他依赖项。

Python: 3.10-alpine Dockerfile

# syntax=docker/dockerfile:1
FROM python:3.10-alpine as base


RUN apk add --update --no-cache --virtual .tmp-build-deps \
gcc g++ libc-dev linux-headers postgresql-dev build-base \
&& apk add libffi-dev


COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

Pyproject.toml 依赖项

python = "^3.10"
Django = "^3.2.9"
djangorestframework = "^3.12.4"
PyYAML = ">=5.3.0,<6.0.0"
Markdown = "^3.3.6"
uritemplate = "^4.1.1"
install = "^1.3.5"
drf-spectacular = "^0.21.0"
django-extensions = "^3.1.5"
django-filter = "^21.1"
django-cors-headers = "^3.10.1"
httpx = "^0.22.0"
channels = "^3.0.4"
daphne = "^3.0.2"
whitenoise = "^6.2.0"
djoser = "^2.1.0"
channels-redis = "^3.4.0"
pika = "^1.2.1"
backoff = "^2.1.2"
psycopg2-binary = "^2.9.3"
pandas = "^1.5.0"