当你为Docker镜像选择基础镜像时,Alpine Linux可能被推荐。有人告诉你,用Alpine将使你的镜像更小,并能加快你的builds。如果你正在用Go,这无疑是个合理的建议。
但如果你使用Python,Alpine Linux会经常:
让你的构建更慢
让你的镜像更大
浪费你的时间
偶尔引入一些令人费解的运行时Bug
让我们看看为什么人们推荐使用Alpine,以及为什么不应该在Python应用程序中使用它。
为什么人们推荐使用Alpine
假设我们需要安装gcc作为镜像构建的一部分,并且我们想看看Alpine Linux在构建时间和镜像大小方面与Ubuntu 18.04有何不同。
首先,我将拉取两个镜像,并检查他们的大小:
$ docker pull --quiet ubuntu:18.04
docker.io/library/ubuntu:18.04
$ docker pull --quiet alpine
docker.io/library/alpine:latest
$ docker image ls ubuntu:18.04
REPOSITORY TAG IMAGE ID SIZE
ubuntu 18.04 ccc6e87d482b 64.2MB
$ docker image ls alpine
REPOSITORY TAG IMAGE ID SIZE
alpine latest e7d92cdc71fe 5.59MB
复制
如你所见,Alpine的基础镜像要小得多。
接下来,我们将尝试在它们两个中安装gcc。首先,在Ubuntu中:
FROM ubuntu:18.04
RUN 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:b6a3ee33acb83148cd273b0098f4c7eed01a82f47eeb8f5bec775c26d4fe4aae
real 0m29.251s
user 0m0.032s
sys 0m0.026s
$ docker image ls ubuntu-gcc
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-gcc latest b6a3ee33acb8 9 seconds ago 150MB
复制
现在,我们编制一个类似的Alpine Dockerfile:
FROM alpine
RUN apk add --update gcc
复制
同样地,构建镜像并检查大小:
$ time docker build -t alpine-gcc -f Dockerfile.alpine --quiet .
sha256:efd626923c1478ccde67db28911ef90799710e5b8125cf4ebb2b2ca200ae1ac3
real 0m15.461s
user 0m0.026s
sys 0m0.024s
$ docker image ls alpine-gcc
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine-gcc latest efd626923c14 7 seconds ago 105MB
复制
就像我们所说的那样,Alpine镜像构建速度更快,体积更小:15秒而不是30秒,镜像大小是105MB而不是150MB。这很好!
但是当我们打包Python应用程序时,情况就开始变得糟糕了。
让我们构建一个Python镜像
我们希望打包一个使用了panda和matplotlib的Python应用程序。因此,一种选择是使用基于Debian的官方Python镜像(我提前拉取的),和以下这个Dockerfile:
FROM python:3.8-slim
RUN pip install --no-cache-dir matplotlib pandas
复制
然后,我们构建它:
$ docker build -f Dockerfile.slim -t python-matpan.
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM python:3.8-slim
---> 036ea1506a85
Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas
---> Running in 13739b2a0917
Collecting 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 b98b5dc06690
Successfully tagged python-matpan:latest
real 0m30.297s
user 0m0.043s
sys 0m0.020s
复制
结果镜像大小为363MB。
用Alpine会获得更好的结果吗?让我们试一试。
FROM python:3.8-alpine
RUN 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