- Так ли мал Alpine 3.8 Docker для Python 3 runtime
- Шаг 2. Установка cython и tornado
- Шаг 3. Добавляем математику numpy scipy
- Шаг 4. Добавляем графический стек websocket-client pytest pandas bokeh pillow
- Итоги
- Alpine собирает Docker билды под Python в 50 раз медленней, а образы в 2 раза тяжелей
- Почему люди рекомендуют Alpine?
- Python образ
- Alpine не поддерживает wheels
- Alpine может быть причиной неожиданных багов в рантайме
- docker learn #06: Hello Python in Alpine
- Installing a Base Image. but Which One?
- Using -ti To Run an Interactive Terminal
- Adding Python3 with the Alpine Package Manager, apk
- Actually Running Python3 in Shell Mode
- Taking on a Small Python Challenge
- Challenge #1: World, Can You Hear Me?
- Challenge #2: Some Maths and Physics
- Wrapping Up
Так ли мал Alpine 3.8 Docker для Python 3 runtime
Совсем недавно произошёл релиз минималистичного Alpine Linux 3.8. Очень часто данный linux образ используют в докере, собирая очень компактные окружения для runtime.
Сегодняшняя статья будет рассмотрена в срезе использования runtime системы в докере для Python 3.6.X версий, с различным составом пакетов pip. А так же мы соберём самый новый Python 3.7 в Alpine.
В конце статьи будет представлен размер образа image, занимаемый на диске, в зависимости от состава пакетов pip и произведено сравнение между дистрибутивами Alpine 3.8, Debian 9, Fedora 28.
Итак, приступим: для тестирования дистрибутивы выбраны. Будем собирать следующие docker images:
- Система, ее обновление. И Python3 с обновлённым pip (10 версии)
- п.1 + tornado cython
- п.2 + numpy-scipy
- п.3 + pillow bokeh pandas websocket-client
В результате даных заливок, мы получим различные версии: Python без пакетов, Python с web сервером, Python с пакетами для обработки многопоточных математических вычислений, Python с «графическим» стеком и работы с данными.
Итак, результирующие файлы для Debian и Fedora будут выглядеть у нас так:
Debian
А вот с Alpine 3.8 пока заминка. Официально на момент написания статьи он ещё на вышел, а посмотреть, то хочется:-). Поэтому нам понадобиться их образ системы:
dl-cdn.alpinelinux.org/alpine/v3.8/releases/x86_64
И мы соберём свой Alpine from Sratch:
github.com/gliderlabs/docker-alpine/tree/master/versions/library-3.8/x86_64
Создаём свой докер файл:
Затем копипастим и добавляем в этот файл борку Python 3.6 со страницы github.com/docker-library/python/blob/master/3.6/alpine3.7/Dockerfile
не забыв удалить или закомментировать строку FROM alpine:3.7
И пробуем создать образ с Alpine 3.8 и Python на борту:
Результаты первого шага установка только Python (docker images —all):
- Debian 9 / 513 MB
- Fedora 28 / 387 MB
- Alpine 3.8 / 82.2 MB
Шаг 2. Установка cython и tornado
Начинаем добавлять пакеты pip. Первым установим cython и tornado. Для Debian и Fedora пакеты ставятся без ошибок, а вот Alpine падает с ошибкой:
Придется гуглить и потом уже добавлять библиотеки сборки в Alpine, чтобы pip успешно собрал их из исходного текста. Затем запускать сборку докера снова, затем опять искать зависимости, читать форумы stackoverflow и issues в github и ждать и ждать и ждать.
Поскольку в следующих шагах мы начнём добавлять математические и графические библиотеки в наш образ runtime Python, и чтобы слишком не увеличивать текст данной статьи, я приведу финальные зависимости для Alpine linux:
- Debian 9 / 534 MB
- Fedora 28 / 407 MB
- Alpine 3.8 / 144 MB
Шаг 3. Добавляем математику numpy scipy
- Debian 9 / 763 MB
- Fedora 28 / 626 MB
- Alpine 3.8 / 404 MB MB
Шаг 4. Добавляем графический стек websocket-client pytest pandas bokeh pillow
- Debian 9 / 905 MB
- Fedora 28 / 760 MB
- Alpine 3.8 / 650 MB
В качестве бонуса, попробуем в Alpine 3.8 скомпилировать ещё не вышедший для докера Python 3.7.
Новая версия Python 3.7 представлена 27 июня 2018 года
Размер Alpine 3.8 с Python 3.7 с текущим списком пакетов pip 656 MB
Итоги
Python
- Debian 9 / больше в 6.24х / +430 Mb
- Fedora 28 / больше в 4,7х / +304 Mb
Python tornado cython
- Debian 9 / больше в 3,71х / +390 Mb
- Fedora 28 / больше в 2,82x / +263 Mb
Python tornado cython numpy scipy
- Debian 9 / больше в 1,88 раз / +359 Mb
- Fedora 28 / больше в 1.54 раз / +222 Mb
Python tornado cython numpy scipy websocket-client pytest pandas bokeh pillow
- Debian 9 / больше в 1,39 раз / +255 Mb
- Fedora 28 / больше в 1.16 раз / +110 Mb
При использовании пустого runtime Python, дистрибутив Alpine linux лидер по минимальному размеру. При увеличени количества библиотек pip до tornado+cython+numpy+scipy Alpine все ещё дает заметную экономию в размере на жёстком диске. Одако как только в пакетах появляются графические утилиты для работы с данными для Python, разница практически исчезает.
При большом количестве графических пакетов, оптимальнее выбрать дистрибутив Fedora, чем заниматься компиляцией пакетов в Alpine (компиляция может длиться 1-2 часа), и в результате получить экономию в один или два десятка процентов места на жёстком диске.
UPDATE1: Тестирование проводилось на Fedora Atomic Host: release 28 (Twenty Eight), Version: 2018.5
Источник
Alpine собирает Docker билды под Python в 50 раз медленней, а образы в 2 раза тяжелей
Alpine Linux — часто рекомендованный как базовый образ для Docker`а. Вам говорят, что использование Alpine сделает ваши билды меньше, а процесс сборки быстрей.
Но если вы используете Alpine Linux для Python приложений, то он:
- Делает ваши билды намного медленней
- Делает ваши образы больше
- Тратит ваше время
- И в итоге может стать причиной ошибок в рантайме
Давайте рассмотрим почему же Alpine рекомендуют, но почему вам все же не стоит использовать его вместе с Python.
Почему люди рекомендуют Alpine?
Давайте предположим, что нам необходим gcc как часть нашего образа и мы хотим сравнить Alpine Linux vs Ubuntu 18.04, по скорости сборки и конечному размеру образа.
Для начала, скачаем два образа и сравним их размер:
Как вы видите, базовый образ для Alpine намного меньше. Давайте теперь попробуем установить gcc и начнем с Ubuntu:
Написание идеальных Dockerfile выходит за рамки этой статьи
Замерим скорость сборки:
Повторяем все то же самое для Alpine (Dockerfile):
Собираем, смотрим на время и размер сборки:
Как и обещано, образы на базе Alpine собираются быстрей и сами по себе меньше: 15 секунда вместо 30 и размер образа 105MB против 150MB. Это довольно хорошо!
Но если мы переключимся на сборку Python приложения, то все не так радужно.
Python образ
Python приложения часто используют pandas и matplotlib. Поэтому, один из вариантов взять официальный образ на базе Debian, используя такой Dockerfile:
Получаем образ размером в 363MB.
Получится у нас лучше с Alpine? Давайте попробуем:
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.
Ах, да, список всех таких зависимостей которые, нужно компилировать придется искать самим.
В данном случае получаем такое:
И время билда занимает…
… 25 минут 57 секунд! А размер образа 851MB.
Образы на базе Alpine собираются намного дольше, сами по себе они большего размера и вам еще нужно искать все зависимости. Можно конечно уменьшить размер сборки используя multi-stage builds но это означает, что нужно проделать еще больше работы.
Alpine может быть причиной неожиданных багов в рантайме
- В теории musl совместим с glibc, но на практике различия могут стать причиной многих проблем. И если они будут, то наверняка неприяные. Вот некоторые проблемы, которые могут возникнуть:
- Alpine по умолчанию имеет меньший размер стека потока, что может привести к ошибкам в Python
- Некоторые пользователи обнаружили, что Python приложения работают медленней из-за того как, musl выделяет память (отличается от glibc).
- Один из пользователей обнаружил ошибку при форматировании даты
Наверняка эти ошибки уже исправили, но кто знает сколько их еще.
Источник
docker learn #06: Hello Python in Alpine
So here I am with a full month of Docker under my belt, wondering what I can do to show myself my progress. To decide what to write about this week, let me start from scratch: what do I know?
I know that to run a docker container, I need a docker image. And to build a docker image, I need a Dockerfile, which contains the files plus metadata necessary to run a self-contained environment. The environment includes an operating system and the application I wish to run. For example, if I want to run a Python3 shell inside a container as if I were running it on my local machine’s terminal, then I’m going to need, at a minimum, the following environment:
- an operating system on which to run Python3
- the Python3 programming language installed on the OS
- a command line interface to interact with Python3 in shell mode
In other words, I need to be able to run the Python3 shell inside a terminal inside a Linux Docker container.
Installing a Base Image. but Which One?
First up is the operating system.
Python is a pretty lightweight language that just about any operating system can handle. So I want to use a super lightweight Linux distribution to serve as my operating system for this exercise. In lieu of Ubuntu, let’s go with Alpine, which is 1/10th the size.
If I run the following command from my Docker CLI, though, I’ll run into trouble right away:
I won’t want to run just this command, because if I do, then this happens:
- my Docker client calls the docker daemon via the Docker API
- it tells the daemon that I want to run an alpine container (totally is true)
- the daemon will dutifully do all this stuff:
- pull the alpine image from Docker Hub 💪🏾
- run the alpine image on my Docker server 💪🏾
- run an alpine container from this image 💪🏾
- immediately exit said container 😤
This is because the Dockerfile for an alpine image has but one command that runs as default: «/bin/sh» .
So when I tell Docker to pull or run alpine, it does that, and the base image runs, and it does what it’s supposed to, but then the shell a) doesn’t receive any additional instructions, b) determines that there is nothing for it to do, and consequently c) stops running, which leaves the container without a process to run, causing the container to be terminated (exited). No process, no container. I get it.
Side Note 1: This can be confirmed with the docker ps -a command, which will show that an alpine container did indeed momentarily run but was then exited.
This is of course no good to me if what I want to do is run Python3 inside a container.
So it’s time to break out the useful -ti flag.
Using -ti To Run an Interactive Terminal
For all the above reasons, I run the following instead:
There we go. Now the docker daemon will do its thing again, but this time, the alpine container won’t exit. The combo of the two Docker flags t and i will instruct Docker to please allocate me a terminal and patiently listen for my input.
I’ll now be able to use the built-in shell to move on to my next step: installing Python3 inside this container.
Adding Python3 with the Alpine Package Manager, apk
Alpine Linux doesn’t come with Python3 pre-installed. You have to install it manually. It’s very simple to do with the alpine package manager, apk . A quick check of the Alpine Linux APK website shows that python3 is indeed one of the packages.
Since I’m now running an Alpine Linux docker container with an interactive terminal waiting for me to provide further instruction, I can proceed:
This will install python3 on my alpine operating system inside the Docker container. I can confirm the installation afterwards by typing python3 —version into the alpine terminal, which outputs Python 3.7.5 :
We’re in business! On to the final step: launching Python3 in shell mode.
Side Note 2: By the way, the presence of / # indicates that I’m in the interactive shell terminal within my alpine container.
Actually Running Python3 in Shell Mode
At last, I can run Python3. Since I just installed python3, I can simply run it by typing python3 :
The presence of >>> indicates that I’m in Python3’s shell mode. That is, I am now actually running the Python3 application. Now for the fun stuff! 😎
Taking on a Small Python Challenge
Now that I have Python running in shell mode inside an interactive shell terminal inside an Alpine Docker container, I can take on a fun challenge. For example, my Educative team recently wrote a blog post with six fun Python challenges.
Let’s try two of them right now :).
Challenge #1: World, Can You Hear Me?
Here was my team’s prompt to readers:
Challenge accepted. In my Docker container, I type this:
And the Python shell prints the following:
Challenge #2: Some Maths and Physics
Here was my team’s prompt to readers:
They also provided the following values:
G = 6.67 x 10^ -11
MSun = 2.0 x 10 30
mEarth = 6.0 x 10 24
r = 1.5 x 10 11
So in my Docker container, I created variables G , M , m , and r and stored their respective values in each, using Python-friendly scientific notation. Then I created the variable grav_force as instructed, though converting it into the Python-friendly notation. Finally, I instructed Python to print the variable I just created, outputting the result of Newton’s beautiful gravitational force equation.
Putting this all together, it was like so:
Close enough, and not bad for this all running inside a Docker container! 🙂
I then type (exit) to exit the Python3 shell, and then exit to exit the alpine container I’ve been using. To confirm that the daemon terminated the container, I use docker ps -a -l , and it shows me that the last container that ran indeed was exited, seconds ago.
Wrapping Up
I’ve once again run out of time to write all the other cool stuff I learned this week or am excited about with respect to Docker. But I’m really happy that I got to «test» myself by starting from what I’ve learned so far and then moving towards a tangible demonstration of my learnings—even crossing over into Python-land.
And did I mention how sweet it is that we just saw how easy and cool it is to run Python-in-Linux-in-Docker?
Источник