Alpine 為 Python 編譯 Docker 版本的速度慢了 50 倍,而鏡像的重量增加了 2 倍

Alpine 為 Python 編譯 Docker 版本的速度慢了 50 倍,而鏡像的重量增加了 2 倍

Alpine Linux 通常被推薦為 Docker 的基礎映像。 您被告知使用 Alpine 將使您的建造更小,建造過程更快。

但如果您將 Alpine Linux 用於 Python 應用程序,那麼它:

  • 使你的建造速度變慢
  • 讓你的圖像更大
  • 浪費你的時間
  • 最終可能會導致運行時錯誤


讓我們看看為什麼推薦 Alpine,但為什麼你仍然不應該將它與 Python 一起使用。

為什麼人們推薦阿爾派?

假設我們需要 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 超出了本文的範圍。

我們來測量一下組裝速度:

$ 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是影像

Python 應用程式經常使用 pandas 和 matplotlib。 因此,一種選擇是使用以下 Dockerfile 來取得基於 Debian 的官方映像:

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('"'"'rn'"'"', '"'"'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

這是怎麼回事?

Alpine 不支援輪子

如果您查看基於 Debian 的構建,您將看到它下載了 matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64。哪兒.

這是車輪的二進位。 Alpine 下載原始檔「matplotlib-3.1.2.tar」。gz` 因為它不支援標準 車輪.

為什麼? 大多數 Linux 發行版都使用 C 標準函式庫的 GNU 版本 (glibc),實際上每個用 C 寫的程式(包括 Python)都需要它。 但 Alpine 使用“musl”,由於這些二進位檔案是為“glibc”設計的,因此它們根本不是一個選項。

因此,如果使用Alpine,則需要編譯每個Python套件中所有用C編寫的程式碼。

哦,是的,您必須查找需要自己編譯的所有此類依賴項的清單。
在這種情況下我們得到這個:

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

建置時間需要...

.... 25分57秒! 圖像大小為851MB。

基於 Alpine 的鏡像的建置時間要長得多,它們的尺寸也更大,而且您仍然需要查找所有依賴項。 您當然可以使用以下方法來縮小組件尺寸 多階段構建 但這意味著還需要做更多的工作。

那不是全部!

Alpine 可能會在運行時導致意外錯誤

  • 理論上,musl 與 glibc 相容,但在實踐中,這些差異可能會導致許多問題。 如果是的話,他們可能會感到不愉快。 以下是可能出現的一些問題:
  • Alpine 預設具有較小的執行緒堆疊大小,這可能會導致 Python 中的錯誤
  • 一些用戶發現 Python 應用程式速度較慢 因為 musl 分配記憶體的方式(與 glibc 不同)。
  • 用戶之一 格式化日期時發現錯誤

當然,這些錯誤已經得到糾正,但誰知道還會有多少。

不要將 Alpine 映像用於 Python

如果您不想費心進行大型且冗長的建置、搜尋依賴項和潛在錯誤,請不要使用 Alpine Linux 作為基礎映像。 選擇一個好的基礎鏡像.

來源: www.habr.com

添加評論