天天看點

還在用Alpine作為Docker的Python開發鏡像?其實Ubuntu更好一點

作者:劉悅技術分享

一般情況下,當你想為你的Python開發環境選擇一個基礎鏡像時,大多數人都會選擇Alpine,為什麼?因為它太小了,僅僅隻有 5 MB 左右(對比 Ubuntu 系列鏡像接近 100 MB),但事實的真相是,我們選擇基礎鏡像并不是為了體驗一下Python文法而已,在此基礎上,我們需要調試和安裝各種擴充,可能會安裝很多三方依賴,甚至預設更多服務,在這種環境下,Alpine就并非是一個很好的選擇了,本次我們就來分别在Alpine和Ubuntu上來體驗一下安裝和編譯Python的差別。

首先分别拉取Alpine和Ubuntu的鏡像:

docker pull ubuntu:18.04
docker pull alpine           

拉取完畢後,可以看到,體積上确實差距明顯:

REPOSITORY                  TAG                   IMAGE ID            CREATED             SIZE
ubuntu                      18.04                 6526a1858e5d        2 weeks ago         64.2MB
alpine                      latest                a24bb4013296        3 months ago        5.57MB           

ubuntu占用64mb,而alpine僅僅5.57mb。

但是先别着急,假設我們的python應用需要做一些科學計算,并且将資料以圖形的方式展示出來,這時候就需要matplotlib和pandas這兩個庫的幫助了,先用ubuntu來安裝這倆個庫,編寫Dockerfile.ubuntu

FROM python:3.7-slim
RUN pip install --no-cache-dir matplotlib pandas           

然後運作鏡像腳本:

docker build -f Dockerfile.ubuntu -t 'ubuntu-mat' .           

可以看到,編譯好的鏡像從原先的60mb暴漲到了263mb。

liuyue:blog liuyue$ docker images
REPOSITORY                  TAG                   IMAGE ID            CREATED              SIZE
ubuntu-mat                  latest                401f0425ce63        About a minute ago   263MB           

使用起來沒有什麼問題。

現在,我們來試試Alpine,看看速度和體積上有沒有比Ubuntu更具優勢

編寫Dockerfile.alpine:

FROM python:3.7-alpine
RUN pip install --no-cache-dir matplotlib pandas           

編譯鏡像腳本

docker build -f Dockerfile.alpine -t 'alpine-mat' .           

在編譯過程中,我們會發現報錯了:

liuyue:blog liuyue$ docker build -f Dockerfile.alpine -t 'alpine-mat' .
Sending build context to Docker daemon  112.1kB
Step 1/2 : FROM python:3.7-alpine
3.7-alpine: Pulling from library/python
df20fa9351a1: Pull complete 
36b3adc4ff6f: Pull complete 
4db9de03f499: Pull complete 
cd38a04a61f4: Pull complete 
6bbb0c43b470: Pull complete 
Digest: sha256:d1375bf0b889822c603622dc137b24fb7064e6c1863de8cc4262b61901ce4390
Status: Downloaded newer image for python:3.7-alpine
 ---> 078114edb6be
Step 2/2 : RUN pip install --no-cache-dir matplotlib pandas
 ---> Running in 6d3c44420e5c
Collecting matplotlib
  Downloading matplotlib-3.3.1.tar.gz (38.8 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-40p0g06u/matplotlib/setup.py'"'"'; __file__='"'"'/tmp/pip-install-40p0g06u/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-pip-egg-info-zk64hzam
         cwd: /tmp/pip-install-40p0g06u/matplotlib/           

這是怎麼搞的?如果你仔細看上面基于Ubuntu的建構,你會發現它下載下傳三方庫的安裝包是matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl,這是一個預編譯的二進制安裝包。而Alpine則隻能下載下傳源代碼(matplotlib-3.1.2.tar.gz)的壓縮包,這就是Alpine的緻命問題:标準的Linux安裝包在Alpine Linux上根本無法使用。

大多數Linux發行版都使用GNU版本的标準C庫(glibc),幾乎所有基于C語言的腳本語言都需要這個庫,包括Python。但Alpine Linux使用的是musl,那些二進制安裝包是針對glibc編譯的,是以Alpine禁用了Linux安裝包支援。現在大多數Python包都在PyPI上包含了二進制安裝包,大大加快了安裝時間。但是如果你使用的是Alpine Linux,你需要編譯你使用的每一個Python包中的所有C源碼。

這也就意味着你需要自己弄清楚每一個系統庫的依賴性。事先編譯好需要的依賴,重新改寫Dockerfile.alpine:

FROM python:3.7-alpine
RUN apk --update add gcc build-base freetype-dev libpng-dev openblas-dev
RUN pip install --no-cache-dir matplotlib pandas           

再次編譯:

docker build -f Dockerfile.alpine -t 'alpine-mat' .           

經過了漫長的編譯安裝,大約半個小時左右,因為我們都知道從源碼編譯安裝要遠遠慢于通過安裝包安裝,此時檢視編譯好的鏡像:

REPOSITORY                  TAG                   IMAGE ID            CREATED              SIZE
alpine-mat                  latest                601f0425ce63        About a minute ago   873MB           

可以看到體積已經變成873mb了,Alpine最引以為傲的體積小輕便等特性也已經蕩然無存。

雖然從理論上講,Alpine使用的musl 核心與其他Linux發行版使用的glibc大多是相容的,但在實際操作中,這種差異可能會造成各種問題。而當這些問題真的發生時,想解決它們就沒那麼簡單了,比如說Alpine的線程預設堆棧容量較小,這會導緻Python崩潰,同時也會影響python應用的運作速度。

結語:在本地環境,如果你隻是想“玩一玩”,那麼基礎鏡像選擇Alpine無可厚非,但是如果你想要将你的python應用部署到生産環境時,特别是部署分布式系統需要多次編譯的場景下,選擇老牌的Ubuntu顯然更加的明智。