Alpine собирает Docker билды под Python в 50 раз медленней, а образы в 2 раза тяжелей

от автора

Alpine Linux — часто рекомендованный как базовый образ для Docker`а. Вам говорят, что использование Alpine сделает ваши билды меньше, а процесс сборки быстрей.

Но если вы используете Alpine Linux для Python приложений, то он:

  • Делает ваши билды намного медленней
  • Делает ваши образы больше
  • Тратит ваше время
  • И в итоге может стать причиной ошибок в рантайме


Давайте рассмотрим почему же Alpine рекомендуют, но почему вам все же не стоит использовать его в месте с Python.

Почему люди рекомендуют Alpine?

Давайте предположим, что нам необходим gcc как часть нашего образа и мы хотим сравнить Alpine Linux vs 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. Поэтому, один из вариантов взять официальный образ на базе Debian, используя такой 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                                ... 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 не поддерживает wheels

Если вы посмотрите на билд, который базируется на Debian, то вы увидите, что он скачивает matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl.

Это бинарник для wheel. Alpine же скачивает исходники `matplotlib-3.1.2.tar.gz`, так как он не поддерживает стандартный wheels.

Почему? Большинство Linux дистрибутивов используют GNU версию (glibc) стандартной библиотеки C, который по факту необходим каждой программе написанной на C, включая Python. Но Alpine использует `musl`, а так как те бинарники предназначены для `glibc`, они попросту не вариант.

Поэтому, если вы используете Alpine, вам необходимо компилировать весь код, написанный на C, в каждом пакете Python.

Ах, да, список всех таких зависимостей которые, нужно компилировать придется искать самим.
В данном случае получаем такое:

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 собираются намного дольше, сами по себе они большего размера и вам еще нужно искать все зависимости. Можно конечно уменьшить размер сборки используя multi-stage builds но это означает, что нужно проделать еще больше работы.

Это еще не все!

Alpine может быть причиной неожиданных багов в рантайме

  • В теории musl совместим с glibc, но на практике различия могут стать причиной многих проблем. И если они будут, то наверняка неприяные. Вот некоторые проблемы, которые могут возникнуть:
  • Alpine по умолчанию имеет меньший размер стека потока, что может привести к ошибкам в Python
  • Некоторые пользователи обнаружили, что Python приложения работают медленней из-за того как, musl выделяет память (отличается от glibc).
  • Один из пользователей обнаружил ошибку при форматировании даты

Наверняка эти ошибки уже исправили, но кто знает сколько их еще.

Не используйте образы Alpine для Python

Если не хотите возиться с большими и долгими билдами, поиском зависимостей и потенциальными ошибками — не используйте Alpine Linux в качестве базового образа. Сhoosing a good base image.

ссылка на оригинал статьи https://habr.com/ru/post/486202/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *