我平时构建 Docker image
的时候,为了减小镜像的大小,方便存储传输,一般都用 alpine 的分发镜像作为
Base image,而且自以为 alpine 和 ubuntu
的区别最大就在于大小和环境全不全,正常用的话,apt->apk
就得了,不过最近在学习用 matplotlib 进行绘图,发现了 alpine
的坑,特此记录一下
镜像构建无法安装 matplotlib
包
我本以为 matplotlib 包与 requests/pandas 等一样,在 alpine 下直接 pip
install 是可以的,实际发现不行🚫,以下是排错过程,着急的电梯在这
➡ 🔗
无法构建镜像
构建镜像失败
提示信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Edit mplsetup.cfg to change the build options; suppress output with --quiet. BUILDING MATPLOTLIB python: yes [3.9.13 (main, May 25 2022, 21:34:36) [GCC 11.2.1 20220219]] platform: yes [linux] tests: no [skipping due to configuration] macosx: no [Mac OS-X only] [end of output] note: This error originates from a subprocess, and is likely not a problem with pip. error: metadata-generation-failed × Encountered error while generating package metadata. ╰─> See above for output. note: This is an issue with the package mentioned above, not pip. hint: See above for details.
进入临时容器排查
1 2 3 4 5 # 启动临时容器测试 docker run --rm -it python:3.9-alpine sh # 安装依赖 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests uvicorn fastapi matplotlib
发现报一样的错误
排除新添加的包测试
1 2 # 先去掉mathplotlib包 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir requests uvicorn fastapi
测试正常
确定问题出在 matplotlib 包导致安装失败
解决过程
尝试搜索关键字 🔍 alpine matplotlib 3.5.2
通过直接安装包尝试
其中,知乎的评论,提示可以通过
apk add py3-matplotlib 实现
安装完成
安装上了,不过确实有点大,246MB... 并且,这个 workaround,并不能解决
pip install matplotlib
报错的问题,安装依旧报同样的错误,并且...产生了一个新问题,👇🏻
添加了一个py3.10...
我这个 base image 是基于 3.9 的,这个又加了一个 3.10
的版本...我裂开...
通过安装编译依赖尝试
Stack Overflow上找到一篇答案,是通过直接添加编译安装的组件解决
1 2 3 4 5 6 7 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip install --upgrade pip setuptools wheel && \ apk add --no-cache --virtual .build-deps gcc g++ zlib-dev make python3-dev py-numpy-dev jpeg-dev && \ pip install matplotlib && \ apk del .build-deps
关于 apk add --virtual 命令相关的解释这个参数就是类似 python 的
virtualenv --target
一样,指定安装的目录,便于后续执行删除操作
报错...
无法安装py-numpy-dev
转而解决安装py-numpy-dev依赖, 依旧是通过Stack Overflow解决的
1 apk --no-cache add musl-dev linux-headers g++
再次尝试安装 matplotlib 包
成功安装
汇总命令如下:
1 2 3 4 5 6 7 8 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories pip install --upgrade pip setuptools wheel apk add --no-cache --virtual .build-deps musl-dev linux-headers g++ gcc zlib-dev make python3-dev jpeg-dev pip install matplotlib apk del .build-deps
不过这个虽然解决了问题,但是编译时间真的太久了...接近 20 分钟了
用时接近 20 分钟
其他参考资料
官方提供的安装手册
Installation
— Matplotlib 3.5.2 documentation
不过并没有 alpine 相关的安装内容,其他环境的可以参考
问题解决
非必要情况,建议直接改用 ubuntu base 的镜像或其他 Linux
完全体镜像。
真的非要用 alpine 作为 base 镜像?确定可以忍受每次构建起步 20
分钟的情况吗?依旧要用的话,下面是命令
1 2 3 4 5 6 7 8 RUN python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip && \ pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \ sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \ pip install --upgrade setuptools wheel && \ apk add --no-cache --virtual .build-deps musl-dev linux-headers g++ gcc zlib-dev make python3-dev jpeg-dev && \ pip install matplotlib && \ apk del .build-deps
反思
这个问题在一开始搜索到知乎的答案的时候其实就明确了,应该直接改用
ubuntu 的
搜索过程中,其实有些博文已经说明了有些情况不适合采用 alpine
作为基础镜像
Using
Alpine can make Python Docker builds 50× slower
翻译版: 用Alpine会让Python
Docker的构建慢50倍 - 腾讯云开发者社区-腾讯云
构建Dockerfile
alpine
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 FROM python:3.9 -alpineMAINTAINER Rex Chow <879582094 @qq.com>ENV TZ='Asia/Shanghai' ENV TIME_OUT=20 ENV LOG_LEVEL='info' ENV CF_ZONE='example.com' COPY app /app WORKDIR /app EXPOSE 80 RUN python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip && \ pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \ sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \ pip install --upgrade setuptools wheel && \ apk add --no-cache --virtual .build-deps musl-dev linux-headers g++ gcc zlib-dev make python3-dev jpeg-dev && \ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir -r /app/requirements.txt && \ apk del .build-deps && \ rm -rf ~/.cache/pip CMD ["sh" , "-c" , "uvicorn main:app --host 0.0.0.0 --port 80 --log-level $LOG_LEVEL " ]
slim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 FROM python:3.9 -slimMAINTAINER Rex Chow <879582094 @qq.com>ENV TZ='Asia/Shanghai' ENV TIME_OUT=20 ENV LOG_LEVEL='info' ENV CF_ZONE='example.com' COPY app /app WORKDIR /app EXPOSE 80 RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir -r /app/requirements.txt && \ rm -rf ~/.cache/pip CMD ["sh" , "-c" , "uvicorn main:app --host 0.0.0.0 --port 80 --log-level $LOG_LEVEL " ]
ubuntu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 FROM python:3.9 MAINTAINER Rex Chow <879582094 @qq.com>ENV TZ='Asia/Shanghai' ENV TIME_OUT=20 ENV LOG_LEVEL='info' ENV CF_ZONE='example.com' COPY app /app WORKDIR /app EXPOSE 80 RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-cache-dir -r /app/requirements.txt && \ rm -rf ~/.cache/pip CMD ["sh" , "-c" , "uvicorn main:app --host 0.0.0.0 --port 80 --log-level $LOG_LEVEL " ]
实际来看, 比对一下最终的构建情况
大小对比
大小对比
时间对比
ubuntu构建时间
slim构建时间
alpine构建时间
数据汇总
环境
原始镜像大小
构建后大小
镜像增长大小
构建时间
alpine
47.4MB
203MB
155.6MB
29m54s
slim
125MB
322MB
197MB
45s
ubuntu
915MB
1.11GB
221.64MB
42s
结论
用仅 120MB 的镜像大小区别,换取每次近 30min
的构建时间,这个是否划算呢?可能真的应了那句话:听人劝,吃饱饭~
Anyway,这次的坑算填上了,就当学习了