Alpine събира Docker билдове под Python 50 пъти по-бавно, а образите са 2 пъти по-големи

Alpine събира Docker билдове под Python 50 пъти по-бавно, а образите са 2 пъти по-големи

Alpine Linux — често препоръчван като основен образ за Docker. Казват ви, че използването на Alpine ще направи вашите билдове по-малки и процесът на изграждане по-бърз.

Но ако използвате Alpine Linux за Python приложения, то той:

  • Прави вашите билдове много по-бавни
  • Прави вашите образи по-големи
  • Отнема вашето време
  • И в крайна сметка може да доведе до грешки по време на работа


Нека разгледаме защо препоръчват 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 излиза извън рамките на тази статия

Нека измерим скоростта на билд:

$ 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.
Изпращане на контекста на изграждането до Docker демона  3.072kB
Стъпка 1/2 : FROM python:3.8-slim
 ---> 036ea1506a85
Стъпка 2/2 : RUN pip install --no-cache-dir matplotlib pandas
 ---> Изпълнява се в 13739b2a0917
Събиране на matplotlib
  Изтегляне на matplotlib-3.1.2-cp38-cp38-manylinux1_x86_64.whl (13.1 MB)
Събиране на pandas
  Изтегляне на pandas-0.25.3-cp38-cp38-manylinux1_x86_64.whl (10.4 MB)
...
Успешно изградена b98b5dc06690
Успешно маркирана python-matpan:latest

реално    0m30.297s
потребител    0m0.043s
система     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 .                                 
Изпращане на контекста на изграждането до Docker демона  3.072kB                                               
Стъпка 1/2 : FROM python:3.8-alpine                                                             
 ---> a0ee0c90a0db                                                                            
Стъпка 2/2 : RUN pip install --no-cache-dir matplotlib pandas                                                  
 ---> Изпълнява се в 6740adad3729                                                                 
Събиране на matplotlib                                                                         
  Изтегляне на matplotlib-3.1.2.tar.gz (40.9 MB)                                               
    ГРЕШКА: Командата приключи с код 1:                                            
     команда: /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                              

...
ГРЕШКА: Командата приключи с код 1: python setup.py egg_info Проверете журналите за пълния изход на командата.
Командата '/bin/sh -c pip install matplotlib pandas' върна код различен от нула: 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 се събират много по-дълго, самите те са с по-голям размер и вие трябва да търсите всички зависимости. Разбира се, можете да намалите размера на сглобяването, като използвате многопластови изграждания но това означава, че трябва да направите още повече работа.

Това не е всичко!

Alpine може да бъде причина за неочаквани грешки по време на изпълнение

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

Сигурно тези грешки вече са поправени, но кой знае колко още има.

Не използвайте образи Alpine за Python

Ако не искате да се занимавате с големи и дълги изграждания, търсене на зависимости и потенциални грешки — не използвайте Alpine Linux като базов образ. Избор на добро базово изображение.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster