发布在即!企业 AIGC 应用程度测评,3 步定制专属评估报告。抢首批测评权益>>> 了解详情
写点什么

用 Alpine 会让 Python Docker 的构建慢 50 倍

  • 2020-03-25
  • 本文字数:3968 字

    阅读完需:约 13 分钟

用Alpine会让Python Docker的构建慢50倍


当你为 Docker 镜像选择基础镜像时,Alpine Linux 可能被推荐。有人告诉你,用 Alpine 将使你的镜像更小,并能加快你的 builds。如果你正在用 Go,这无疑是个合理的建议。


但如果你使用 Python,Alpine Linux 会经常:


  1. 让你的构建更慢

  2. 让你的镜像更大

  3. 浪费你的时间

  4. 偶尔引入一些令人费解的运行时 Bug


让我们看看为什么人们推荐使用 Alpine,以及为什么不应该在 Python 应用程序中使用它。

为什么人们推荐使用 Alpine

假设我们需要安装 gcc 作为镜像构建的一部分,并且我们想看看 Alpine Linux 在构建时间和镜像大小方面与 Ubuntu 18.04 有何不同。


首先,我将拉取两个镜像,并检查他们的大小:


$ docker pull --quiet ubuntu:18.04docker.io/library/ubuntu:18.04$ docker pull --quiet alpinedocker.io/library/alpine:latest$ docker image ls ubuntu:18.04REPOSITORY          TAG        IMAGE ID         SIZEubuntu              18.04      ccc6e87d482b     64.2MB$ docker image ls alpineREPOSITORY          TAG        IMAGE ID         SIZEalpine              latest     e7d92cdc71fe     5.59MB
复制代码


如你所见,Alpine 的基础镜像要小得多。


接下来,我们将尝试在它们两个中安装 gcc。首先,在 Ubuntu 中:


FROM ubuntu:18.04RUN apt-get update && \    apt-get install --no-install-recommends -y gcc && \    apt-get clean && rm -rf /var/lib/apt/lists/*
复制代码


注意:在我们讨论的主题之外,本文中的 Dockerfile 并不是最佳实践的示例,因为增加的复杂性会掩盖本文的主要观点。因此,如果你打算用 Docker 在生产环境中运行你的 Python 应用程序,这里有两种方法可以应用最佳实践:


如果你想 DIY:一个详细的清单、例子和参考资料


如果你想要尽快拥有一个基本够用的设置:一个模板和为你实现的最佳实践


然后,我们可以构建并记录时间:


$ time docker build -t ubuntu-gcc -f Dockerfile.ubuntu --quiet .sha256:b6a3ee33acb83148cd273b0098f4c7eed01a82f47eeb8f5bec775c26d4fe4aaereal    0m29.251suser    0m0.032ssys     0m0.026s$ docker image ls ubuntu-gccREPOSITORY   TAG      IMAGE ID      CREATED         SIZEubuntu-gcc   latest   b6a3ee33acb8  9 seconds ago   150MB
复制代码


现在,我们编制一个类似的 Alpine Dockerfile:


FROM alpineRUN apk add --update gcc
复制代码


同样地,构建镜像并检查大小:


$ time docker build -t alpine-gcc -f Dockerfile.alpine --quiet .sha256:efd626923c1478ccde67db28911ef90799710e5b8125cf4ebb2b2ca200ae1ac3real    0m15.461suser    0m0.026ssys     0m0.024s$ docker image ls alpine-gccREPOSITORY   TAG      IMAGE ID       CREATED         SIZEalpine-gcc   latest   efd626923c14   7 seconds ago   105MB
复制代码


就像我们所说的那样,Alpine 镜像构建速度更快,体积更小:15 秒而不是 30 秒,镜像大小是 105MB 而不是 150MB。这很好!


但是当我们打包 Python 应用程序时,情况就开始变得糟糕了。

让我们构建一个 Python 镜像

我们希望打包一个使用了 panda 和 matplotlib 的 Python 应用程序。因此,一种选择是使用基于 Debian 的官方 Python 镜像(我提前拉取的),和以下这个 Dockerfile:


FROM python:3.8-slimRUN pip install --no-cache-dir matplotlib pandas
复制代码


然后,我们构建它:


$ docker build -f Dockerfile.slim -t python-matpan.Sending build context to Docker daemon  3.072kBStep 1/2 : FROM python:3.8-slim ---> 036ea1506a85Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas ---> Running in 13739b2a0917Collecting matplotlib  Downloading matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)Collecting pandas  Downloading pandas-0.25.3-cp38-cp38-manylinux1_x86_64.whl (10.4 MB)...Successfully built b98b5dc06690Successfully tagged python-matpan:latestreal    0m30.297suser    0m0.043ssys     0m0.020s
复制代码


结果镜像大小为 363MB。


用 Alpine 会获得更好的结果吗?让我们试一试。


FROM python:3.8-alpineRUN pip install --no-cache-dir matplotlib pandas
复制代码


然后,我们构建它:


$ docker build -t python-matpan-alpine -f Dockerfile.alpine .                                 Sending build context to Docker daemon  3.072kB                                               Step 1/2 : FROM python:3.8-alpine                                                              ---> a0ee0c90a0db                                                                            Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas                                                   ---> Running in 6740adad3729                                                                 Collecting matplotlib                                                                           Downloading matplotlib-3.1.2.tar.gz (40.9 MB)                                                   ERROR: Command errored out with exit status 1:                                                 command: /usr/local/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-a3olrixa/matplotlib/setup.py'"'"'; __file__='"'"'/tmp/pip-install-a3olrixa/matplotlib/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-a3olrixa/matplotlib/pip-egg-info                              ...ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.The command '/bin/sh -c pip install matplotlib pandas' returned a non-zero code: 1
复制代码


发生了什么?

标准的 PyPI wheel 在 Alpine 上无效

如果你仔细查看上面基于 Debian 的构建,就会看到它正在下载 matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl。这是一个预编译的二进制 wheel。与此相反,Alpine 会下载源代码(matplotlib-3.1.2.tar.gz),因为标准的 Linux wheel 在 Alpine Linux 上无效。


为什么?大多数 Linux 发行版使用标准 C 库的 GNU 版本(glibc),Python 以及几乎所有的 C 程序都需要它。但是 Alpine Linux 使用 musl,这些二进制 wheel 是针对 glibc 编译的,因此 Alpine 禁用了 Linux wheel 支持。


现在,大多数 Python 包都包含了 PyPI 上的二进制 wheel,这大大缩短了安装时间。但是,如果你使用的是 Alpine Linux,那么你就需要编译你所使用的每个 Python 包中的所有 C 代码。


这也意味着你需要自己找出每个系统库依赖项。在这种情况下,为了找出依赖项,我做了一些研究,最后得到下面这个经过更新的 Dockerfile:


FROM python:3.8-alpineRUN apk --update add gcc build-base freetype-dev libpng-dev openblas-devRUN pip install --no-cache-dir matplotlib pandas
复制代码


然后我们构建它,它需要……25 分钟 57 秒!得到的镜像是 851MB。


下面是两个基本镜像的对比:



Alpine 的构建速度要慢得多,镜像要大得多,而且我不得不做了很多研究。

你不能解决这些问题吗?

构建时间

为了缩短构建时间,Alpine Edge(最终将成为下一个稳定版本)会包含 matplotlib 和 panda。而且安装系统包非常快。但是,到 2020 年 1 月为止,当前的稳定版本还不包括这些流行的包。


然而,即使它们可用了,系统包也几乎总是滞后于 PyPI 上的包,Alpine 也不太可能打包 PyPI 上的所有东西。据我所知,在实践中,大多数 Python 团队并没有将系统包用于 Python 依赖项,而是依赖于 PyPI 或 Conda Forge。

镜像大小

一些读者指出,你可以删除最初安装的包,或者添加不缓存包下载的选项,或者使用多阶段构建。一位读者尝试生成了一个470MB的镜像


是的,你可以得到一个与基于 slim 的镜像大致相当的镜像,但是 Alpine Linux 的全部动机是更小的镜像和更快的构建。如果工作做够了,你可能会得到一个更小的镜像,但是你仍然要忍受长达 1500 秒的构建时间,当你使用 python:3.8-slim 镜像时,构建时间只有 30 秒。


但是等等,还有!

Alpine Linux 会导致意料之外的运行时 Bug

虽然理论上,Alpine 使用的 musl C 库与其他 Linux 发行版使用的 glibc基本兼容,但在实践中,这种差异可能会导致问题。当问题确实发生时,可能会很奇怪且出乎意料。


下面是一些例子:


  1. Alpine 线程的默认堆栈大小更小,这可能导致Python崩溃

  2. Alpine 的一位用户发现,由于 musl 分配内存的方式与 glibc 不同,他们的 Python 应用程序要慢很多

  3. 在使用 WeWork 工作空间的 WiFi 时,我曾经无法在 minikube(虚拟机中的 Kubernetes)上运行的 Alpine 镜像中查找 DNS。原因是 WeWork 糟糕的 DNS 设置、Kubernetes 和 minikube 实现 DNS 的方式,以及 musl 对这种边缘情况的处理与 glibc 的方式不同。musl 没有错(它符合 RFC),但是我不得不浪费时间找出问题所在,然后切换到基于 glibc 的镜像。

  4. 另一个用户发现了时间格式和解析的问题。


大多数或者说所有这些问题可能都已经得到解决,但毫无疑问,还有更多的问题有待发现。这种出人意料的破坏是又一件需要担心的事情。

不要将 Alpine Linux 用于 Python 镜像

除非你想要更长的构建时间、更大的镜像、更多的工作,以及潜在的隐藏 Bug,否则你应该避免使用 Alpine Linux 作为基础镜像。


关于应该使用哪些镜像的建议,请参阅我的文章“选择一个好的基础镜像”。


英文原文:


Using Alpine can make Python Docker builds 50× slower


2020-03-25 15:479497
用户头像

发布了 683 篇内容, 共 391.1 次阅读, 收获喜欢 1498 次。

关注

评论 5 条评论

发布
用户头像
这个标题吓到我了,图片也是乱配。一看,哦,营销号,乱写就行了。
2020-06-18 09:12
回复
用户头像
什么鬼啊?
2020-06-18 09:11
回复
用户头像
用Ubuntu基础镜像时使用了习惯良好的构建方式,使用alpine基础镜像却比较随意。能不能去看看别人用alpine基础镜像打包的python镜像多大。得出这种结论的人,不太理解Docker,不要自己构建了,用官方提供的就行了
2020-03-27 19:26
回复
同意。没有理解alpine的特点在哪里,小巧的同时必然会牺牲一些库,要无脑省心还是跑在完整版的虚拟机里吧。
2020-03-31 11:12
回复
用户头像
自己不会构建,不要怪基础镜像
2020-03-27 19:23
回复
没有更多了
发现更多内容

2023京津冀(北京)广告印刷技术与设备博览会

吹吹晚风

浅议实时操作系统RTOS

DevOps和数字孪生

RTOS 实时操作系统

点云标注在自动驾驶中有着广泛的应用案例

来自四九城儿

18款iPad绘画软件推荐!iPad必备生产力工具。

彭宏豪95

ipad 效率工具 苹果 绘图软件 在线绘图

使用 Postman 批量发送请求实用教程

Liam

Java 后端 开发 Postman API

java面试题-多线程

程序员小张

多云管理平台有哪些?大家推荐哪家好用?

行云管家

云计算 多云 云管理 云管

如何看待互联网大厂加班文化?

程序员小毕

程序员 互联网 后端 架构师 java面试

揭秘|来看看袋鼠云数栈内部的资产血缘方案设计与实现

袋鼠云数栈

数据资产 数据血缘

m7s Console架构解析

不卡科技

vite 流媒体 控制台 Vue 3 #go

跟着核心开发者聊聊大模型应用、框架开源那些事儿

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

携手生态共筑数智底座,加速企业数智化转型

用友BIP

数智底座

软件测试/测试开发丨Python 面向对象编程思想

测试人

Python 编程 面向对象 软件测试

2023中国(北京)国际数字标牌展览会

吹吹晚风

多种应用场景下的大数据传输解决方案,让企业数据高效同步

镭速

大数据传输

DevSecOps:软件安全捍卫者

DevOps和数字孪生

DevSecOps

成都站|阿里云 Serverless 技术实战营邀你来玩!

Serverless Devs

云计算 负载均衡 Serverless 云原生 弹性计算

五种高级 NodeJS 技术

互联网工科生

node.js nodejs

电商企业需要堡垒机吗?采购堡垒机选择哪家好?

行云管家

网络安全 信息安全 电商 堡垒机 等级保护

汽车软件的模糊测试

DevOps和数字孪生

软件定义汽车

【参考设计】100 W USB PD 3.0电源

元器件秋姐

设计 电路 方案 usb 电源

4种大文件传输的方式?适用设计类企业的文件传输方法

镭速

大文件传输

Ubuntu 20.04系统编译安装Memcached教程。

百度搜索:蓝易云

memcached 云计算 Linux ubuntu 运维

柏睿数据作为湖仓一体数据平台代表厂商入选IDC报告

新消费日报

构建网站利器!体验高速稳定的香港云主机服务!

一只扑棱蛾子

云主机 香港云主机

EDS从小白到专家丨打造你的专属“数据物流”系统

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

混战源起ChatGPT,中国的AI产业怎么样了? | 社区征文

向阳花

人工智能 AI 马斯克 前沿技术 年中技术盘点

Python案例实现|爬取租房网站信息

TiAmo

Python 数据分析

Ubuntu 20.04系统编译安装Redis教程。

百度搜索:蓝易云

redis 云计算 Linux ubuntu 运维

中小企业建设数字化工厂,选择集成老路还是整体重构?

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

网络带宽利用率不够?这些大数据传输解决方案来帮你

镭速

数据传输 大数据传输

用Alpine会让Python Docker的构建慢50倍_文化 & 方法_Itamar Turner-Trauring_InfoQ精选文章