暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Docker中使用pyinstaller 又如何?

写程序的日子 2020-07-21
2617

使用 docker
 打包 python
 项目时,如何让镜像小一点,一直不太理想。

常见的python 项目,动则就是几百M 甚至上G 的镜像大小。

我能理解,我所依赖的第三方库越多,最后镜像肯定就越大,例如python 里面的很多算法库,都是几十上百M,特别是一些动态的依赖 —— 依赖于linux上的软件,在运行时需要,无法卸载掉来减少镜像大小 —— 镜像整体就会更大,达到论 G 算。

但是如果项目本身小,同时依赖的第三方库少,系统运行依赖少甚至无,我该如何尽量减小镜像的大小?

以Docker Hub 中python官方维护的镜像为例,一个简单的python3.6 环境,就算是alpine,也至少有70M,远远大于我们的代码 —— 一两个简单源码文件,当通过 FROM python:3.6-alpine
 后,镜像大小就向100M 看齐了。

那该如何来缩小python 镜像的大小呢?

常见操作
  1. # 继承自一个python+linux 环境

  2. FROM python:3.6-slim

  3. # 拷贝项目文件

  4. COPY xxx/ /projects/

  5. ENV TZ=Asia/Shanghai

  6. WORKDIR /project

  7. USER root

  8. # 系统安装软件 debian 系,不安装推荐软件

  9. RUN apt-get update \

  10. && apt-get install -y --no-install-recommends xxx xxx

  11. # 安装python第三方库,no-cache-dir 用于不使用本地下载缓存,同时清理不需要的linux 安装和日志,

  12. RUN pip install --no-cache-dir requirements.txt \

  13. && apt-get clean \

  14. && apt-get --purge autoremove -y gcc \

  15. && rm -rf /tmp/* /var/lib/apt/* /var/cache/* /var /log/*

  16. # web 应用指定端口

  17. EXPOSE 8080

  18. CMD ["python","xxx.py"]

这是最常见的镜像打包过程,通过去掉安装过程生成的不必要的文件来缩小镜像,但镜像本身不够小,也不会特别大。

这里需要说明一下,python 的官方镜像分为基于alpine
buster
, stretch
 和 slim
 的四种。其中,buster
stretch
标签的镜像约900M,因为过大而通常不选择,alpine
镜像约5-7M,但因为包管理不同,以及使用不同的C库(不是更常见的glibc)可能会导致奇怪的问题,也不是一个首选方案。

所以一般是选择标签slim
:镜像大小约150M。

这样的思路,几乎能够适用于各种项目,打包镜像结果会根据依赖多少而呈现出不同的大小 —— 甚至,更推荐那种依赖复杂一点的应用,以这种方式发布。

那如果 python 项目本身并不大,甚至第三方库很少,无系统依赖(定位于,微小的应用,微小的服务),使用python:slim
 标签镜像至少150M ,python: alpine
 标签镜像也至少70M ,又能如何缩小镜像大小呢?

非常规操作

目前的想法和尝试,主要是基于pyinstaller 的编译,和Dockerfile 的多阶段构建

  • python:3.6-alpine
     编译,alpine:3.12
     中运行

这里的思路是,通过pyinstaller 编译后,选择没有python 的环境,来运行脚本。

值得注意的是,alpine
上相关依赖安装麻烦(参考文献不多),alpine
 上pyinstaller 坑很多。

但是这样的方式,打包出来的镜像,如果项目小(单个文件,一行代码为例),大概就11M+。

  1. FROM bigpangl/python:3.6-alpine-pyinstaller3.4

  2. WORKDIR /app

  3. COPY app.py ./app.py


  4. RUN apk --update --no-cache add g++ scons patchelf \

  5. && pip install staticx \

  6. && pyinstaller -F app.py


  7. FROM bigpangl/alpine:3.12

  8. COPY --from=complier /app/dist/app /app

  9. CMD ./app

  • python:3.6-slim
     编译,alpine:3.12
    中运行

选择slim
 上编译是因为alpine
上编译,问题太多了,以我为代表的人群,可能无法搜寻到解决方案,slim
基于debian
,参考资料多了很多。

但是需要在编译后,通过python 的第三方库staticx
(Bundle dynamic executables with their library dependencies so they can be run anywhere, just like a static executable.) 进行再次打包。这样的项目,打包镜像基础大概12M+

  1. FROM bigpangl/python:3.6-slim AS complier

  2. WORKDIR /app

  3. COPY app.py ./app.py


  4. RUN apt-get update && apt-get install -y build-essential patchelf \

  5. && pip install staticx pyinstaller && pyinstaller -F app.py && staticx /app/dist/app /app


  6. FROM bigpangl/alpine:3.12

  7. WORKDIR /app

  8. COPY --from=complier /app /app

  9. CMD ./app

关于staticx

我本以为它的目的是,打包静态可执行文件。然后我就可以用 scratch 镜像了 —— 但是,好像不能?


文章转载自写程序的日子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论