Как превратить скрипт на Python в «настоящую» программу при помощи Docker +29


AliExpress RU&CIS

Никого не интересует, умеете ли вы разворачивать связанный список — всем нужно, чтобы можно было легко запускать ваши программы на их машине. Это становится возможным благодаря Docker.


Для кого предназначена эта статья?


Вам когда-нибудь передавали код или программу, дерево зависимостей которой напоминает запутанную монтажную плату?


Как выглядит управление зависимостями

Без проблем, я уверен, что разработчик любезно предоставил вам скрипт установки, чтобы всё работало. Итак, вы запускаете его скрипт, и сразу же видите в оболочке кучу сообщений логов ошибок. «У меня на машине всё работало», — обычно так отвечает разработчик, когда вы обращаетесь к нему за помощью.

Docker решает эту проблему, обеспечивая почти тривиальную портируемость докеризованных приложений. В этой статье я расскажу, как быстро докеризировать ваши приложения на Python, чтобы ими можно было легко делиться с любым человеком, у которого есть Docker.

В частности, мы рассмотрим скрипты, которые должны работать как фоновый процесс.

Репозитории Github и Docker


Если вам более удобна наглядность, то изучите репозитории Github и Docker, где будет хоститься этот код.

Но… почему Docker?


Контейнеризацию можно сравнить с размещением вашего ПО в грузовом контейнере, обеспечивающем стандартный интерфейс для компании-грузоперевозчика (или другого компьютера-хоста), который позволяет взаимодействовать с ПО.

Контейнеризация приложений на самом деле является золотым стандартом портируемости.


Общая схема Docker/контейнеризации

Контейнеризация (особенно при помощи docker) открывает перед вашим программным приложением огромные возможности. Правильно контейнеризированное (например, докеризированное) приложение можно развёртывать с возможностью масштабирования через Kubernetes или Scale Sets любого поставщика облачных услуг. И да, об этом мы тоже поговорим в следующей статье.

Наше приложение


В нём не будет ничего особо сложного — мы снова работаем с простым скриптом, отслеживающим изменения в каталоге (так как я работаю в Linux, это /tmp). Логи будут передаваться на stdout, и это важно, если мы хотим, чтобы они отображались в логах docker (подробнее об этом позже).


main.py: простое приложение мониторинга файлов

Эта программа будет выполняться бесконечно.

Как обычно, у нас есть файл requirements.txt с зависимостями, на этот раз только с одной:


requirements.txt

Создаём Dockerfile


В моей предыдущей статье мы создали скрипт процесса установки в Makefile, благодаря чему им очень легко делиться. На этот раз мы сделаем нечто подобное, но уже в Docker.


Dockerfile

Нам необязательно вдаваться в подробности устройства и работы Dockerfile, об этом есть более подробные туториалы.

Краткое описание Dockerfile — мы начинаем с базового образа, содержащего полный интерпретатор Python и его пакеты, после чего устанавливаем зависимости (строка 6), создаём новый минималистичный образ (строка 9), копируем зависимости и код в новый образ (строки 13–14; это называется многоэтапной сборкой, в нашем случае это снизило размер готового образа с 1 ГБ до 200 МБ), задаём переменную окружения (строка 17) и команду исполнения (строка 20), на чём и завершаем.

Сборка образа


Завершив с Dockerfile, мы просто выполняем из каталога нашего проекта следующую команду:

sudo docker build -t directory-monitor .


Собираем образ

Запуск образа


После завершения сборки можно начинать творить магию.

Один из самых замечательных аспектов Docker заключается в том, что он предоставляет стандартизованный интерфейс. Так что если вы правильно спроектируете свою программу, то передавая её кому-то другому, достаточно будет сказать, что нужно изучить docker (если человек ещё его не знает), а не обучать его тонкостям устройства вашей программы.

Хотите увидеть, что я имею в виду?

Команда для запуска программы выглядит примерно так:


Здесь многое нужно объяснить, поэтому разобьём на части:

-d — запуск образа в detached mode, а не в foreground mode

--restart=always — при сбое контейнера docker он перезапустится. Мы можем восстанавливаться после аварий, ура!

--e DIRECTORY='/tmp/test' — мы передаём при помощи переменных окружения каталог, который нужно отслеживать. (Также мы можем спроектировать нашу программу на python так, чтобы она считывала аргументы, и передавать отслеживаемый каталог таким способом.)

-v /tmp/:/tmp/ — монтируем каталог /tmp в каталог /tmp контейнера Docker. Это важно: любой каталог, который мы хотим отслеживать, ДОЛЖЕН быть видимым нашим процессам в контейнере docker, и именно так это реализуется.

directory-monitor — имя запускаемого образа

После запуска образа его состояние можно проверять с помощью команды docker ps:


Вывод docker ps

Docker создаёт crazy-имена для запущенных контейнеров, потому что люди не очень хорошо запоминают значения хэшей. В данном случае имя crazy_wozniak относится к нашему контейнеру.

Теперь, поскольку мы отслеживаем /tmp/test на моей локальной машине, если я создам в этом каталоге новый файл, то это должно отразиться в логах контейнера:


Логи Docker демонстрируют, что приложение работает правильно

Вот и всё, теперь ваша программа докеризирована и запущена на вашей машине. Далее нам нужно решить проблему передачи программы другим людым.

Делимся программой


Ваша докеризированная программа может пригодиться вашим коллегам, друзьям, вам в будущем, да и кому угодно в мире, поэтому нам нужно упростить её распространение. Идеальным решением для этого является Docker hub.

Если у вас ещё нет аккаунта, зарегистрируйтесь, а затем выполните логин из cli:


Логинимся в Dockerhub

Далее пометим и запушим только что созданный образ в свой аккаунт.


Добавляем метку и пушим образ


Теперь образ находится в вашем аккаунте docker hub

Чтобы убедиться, что всё работает, попробуем выполнить pull этого образа и использовать в сквозном тестировании всей проделанной нами работы:


Сквозное тестирование нашего образа docker

Весь этот процесс занял всего 30 секунд.

Что дальше?


Надеюсь, мне удалось убедить вас в потрясающей практичности контейнеризации. Docker останется с нами надолго, и чем раньше вы его освоите, тем больше получите преимуществ.

Суть Docker заключается в снижении сложности. В нашем примере это был простой скрипт на Python, но можно использовать этот туториал и для создания образов произвольной сложности с деревьями зависимостей, напоминающими спагетти, но конечного пользователя эти трудности не коснутся.

Источники






На правах рекламы


Вдсина предлагает виртуальные серверы на Linux или Windows. Используем исключительно брендовое оборудование, лучшую в своём роде панель управления серверами собственной разработки и одни из лучших дата-центров в России и ЕС. Поспешите заказать!




Комментарии (35):

  1. aamonster
    /#22993414

    Статья, как завернуть скрипт в образ виртуальной машины, планируется?

  2. kaleman
    /#22993466

    А может проще написать "настоящую" программу на настоящем языке? Тогда и докер не понадобится.

    • bugy
      /#22993516

      Какие программы являются настоящими? И какие языки?
      Я как пользователя линукса довольно редко встречаю "настоящие" программы. Или линукс тоже ненастоящая ОС?

      • Arenoros
        /#22993536

        интересно, как же ты обходишься без ls, bash, cp, cd и сотни друхих шелл команд?))

        • bugy
          /#22993596

          Когда изредка приходится пользоваться виндой, обхожусь без них с большим неудобством :)
          И сотня команд по сравнению с миллионнами всех программ это капля в море.


          Чаще всего софт делают для винды/мака. А на линуксе альтернативы.


          И чаще всего это вопрос не языка, а именно адаптации под ОС

          • Arenoros
            /#22993614 / -1

            совсем не понял почему ты перепрыгнул на винду и мак когда сам говрил про linux, но отвечу про «настоящие языки», очевидно те что не требуют эмулировать целую ОС, для запуска hello world в виде бинаря, в чём смысл брать скриптовый язык и пытаться создать из него бинарь не лучше ли взять для этого более подходящий компилируемый язык? к тому же для питон есть более «адекватная» реализация этого. Использовать докер контейнер только для того чтоб запихнуть 1 скрипт, это уже верх маразма…

            • bugy
              /#22993756 / +1

              Запуск скрипта/программы требует подходящего окружения, иначе толку с него, если он запускается только у вас.


              Например, в подходящее окружение входят:


              • ОС
              • зависимости, например на питоновские либы или 3rd party tools (например на тот же bash)
              • таймзоны
                Докер все эти проблемы и решает.

              Языки (компилируемые или нет) не могут решить эти проблемы и/или требуют чрезмерного усложнения скрипта. Компилируемые языки тут не сильно помогают.


              Да, ненативная компиляция (например java/python), может увеличивать количество проблем с окружением. Но в то же время не требует создавать бинарники под каждую ОС.


              Я соглашусь с вами, что докер для запуска скриптов, это чаще всего нехилый и ненужный оверхед. Но и не обязательно это делать каждый раз. Важно знать, что такой подход существует и может быть оправдан в некоторых случаях.

        • chupasaurus
          /#22995664

          Из озвученного cd не является программой.

  3. Tinkz
    /#22993484

    с любым человеком, у которого есть Docker.
    дальше не читал ибо докера ни у кого нет

  4. tmin10
    /#22993640

    Как-то немного странно видеть докер для решения задач распостранения программ. Понятно, что если вам надо это разворачивать где-то в кластере, но другое дело если вы говорите конечным пользователям, что для работы нашего питон скрипта нужен докер… Докер имадж может быть одной из опций, но не основновным вариантом, как мне кажется.

    • raamid
      /#22993714

      Проблема в том, что это может быть не просто скрипт, а например сервер на Django с множеством зависимостей, причем бывает и так, что требуются конкретные версии, самые новые не подходят. И когда таких «скриптов» на компьютере несколько, их обвязка (библиотеки, БД) может мешать друг другу.

      • tmin10
        /#22993724

        Как хорошо, что существует venv, который позволит решить эту проблему :)

        • raamid
          /#22993752

          А если у вас в проекте не только Python, а еще БД, задачи, выполняемые по расписанию, настройки часового пояса?

          • Tamahome
            /#22994656 / -1

            а что мешает собрать пачку докеров в один docker-compose...?

          • andreymal
            /#22995494

            Это всего лишь две дополнительные команды (для начального заполнения БД и для запуска celery beat), никакой докер тут не требуется

            • ReDev1L
              /#22995860

              Ага и тонны мануалов по установке и настройке этих БД + совместимость версий.

              • andreymal
                /#22996466

                по установке

                apt install mariadb-server занимает примерно секунд пять


                и настройке этих БД

                А при установке из докера всё окажется магическим образом автоматически оптимизировано конкретно под мою систему и настраивать ничего не надо, что ли?


                совместимость версий

                С этим проблем нет, если система не из прошлого тысячелетия

                • ReDev1L
                  /#22998232

                  1. Нет смысла комментить.
                  2. Энвы в контейнер с базой, либо example conf в репе + описание что менять под этот проект.
                  3. В МашаБД мб нет, не знаю, а вот с MySQL 5.7 vs 8 есть. Это самый простой пример. Рассказывать нам как Вы умеете ставить миллион бд чтобы они работали параллельно не надо. Это лютый гемор без контейнеров.

                  • andreymal
                    /#22998268

                    Энвы в контейнер с базой, либо example conf в репе + описание что менять под этот проект.

                    Ну то есть настраивать в любом случае придётся. В чём проблема сделать точно такой же example conf без контейнеров?


                    Это лютый гемор без контейнеров.

                    Ну вот и устанавливайте MySQL в контейнерах сколько вам угодно, я не против. А python-проекты в контейнер пихать зачем? Все основные питоновые ORM поддерживают широкий набор СУБД от MySQL 5.7 до MariaDB 10.5, плюс прочие постгресы и sqlite3. Если не использовать заведомо несовместимые фичи, специфичные для конкретной СУБД, то проблем с совместимостью не будет.

                    • ReDev1L
                      /#22998322

                      Вам — не зачем) а мне — для спокойствия, порядка и чистоты.

                      • andreymal
                        /#22998336

                        Для спокойствия, порядка и чистоты я избегаю использования контейнеров ?\_(?)_/?

    • Tamahome
      /#22994646 / +1

      добро пожаловать в долбаную реальность, везде и всюду вендорский софт в докере, дак еще и в venv… так как библиотеки которые использовали протухли еще за пару лет до релиза первой беты.."

    • glader
      /#22999452

      Запускаю торрент-клиент в докере, очень нравится.

  5. jsirex
    /#22993848 / +1

    Что-то начинает напрягать реклама в которой ещё есть и hello-world статья.

    Пора и мне на хабре написать:
    Название: Основы программирования за 5 минут
    Текст:
    Давайте выведем 2+2:

    echo "2+2 = 4"

    Ну вот, мы научились. Да, тут есть что улучшить, но купите наши вазелиновые шарики всего за 9.99. первым 100 000 покупателей скидка 2 копейки.

  6. HeaTTheatR
    /#22993902

    Для таких вещей люди придумал PyInstaller для Windows и Mac, который справляется на 100% со своей задачей, и AppImage для Linux.

  7. uyrij
    /#22994036

    Добавлю пять копеек. Есть мультиплатформеная conda/anaconda
    conda -n "хелворд" -python=какая версия нужна conda-pack
    Conda activate хелворд
    Пишем, что хотим, после conda-pack получаем tarball.gz со всеми установленными зависимостями. На целевой машине достаточно поставить конду батником и распаковать архив 7zip или нативно в линуксе

  8. 19as
    /#22994360

    Не будут рады пользователи Winsows такому "правильному и настоящему" запуску приложений

    • mistergrim
      /#22996028

      Пользователи Windows смотрят в сторону PY2EXE и недоумевают, зачем вот это вот всё.

  9. Griboks
    /#22994382

    Согласен, управление окружениями в питоне хуже некуда (но хотя бы лучше nodejs).
    Но всё-таки компилировать программу лучше на сборочном сервере/контейнере, чем поставлять эти контейнеры с аж целым докером.

  10. AVX
    /#22995272

    Извините, если покажется рекламой (не реклама, личный опыт), но всё-таки про докер — посоветую курс на kodekloud: Docker for the Absolute Beginner — Hands On
    Там на английском, но вполне понятно, есть субтитры, кто голос плохо воспринимает (как я). И этот курс бесплатен (в отличие от множества остальных на том сайте).

  11. ReDev1L
    /#22995866

    А можно не писать раз в месяц статью на хабр как засунуть в докер helloworld?

  12. 3vi1_0n3
    /#22996494

    Рискую нахватать минусов, но таки скажу.
    Что только люди не делают, лишь бы на баше не писать.
    Пример из статьи решается при помощи «apt install inotify-tools» и скриптом на баше примерно такого же размера как скрипт на питоне из статьи, а то и меньше.
    Образ докера из статьи 114 Mb. Плюс докер, чтобы эти 114Mb запускать.
    Пакет inotify-tools:

    Пол:1 http://deb.debian.org/debian bullseye/main amd64 libinotifytools0 amd64 3.14-8.1 [18.9 kB]
    Пол:2 http://deb.debian.org/debian bullseye/main amd64 inotify-tools amd64 3.14-8.1 [25.9 kB]

    44.8 Kb, В распакованном виде 150 Kb. Во сколько я это затолкаю в контейнер даже проверять нет желания.

    Единственная причина, почему автор вот это вот всё сделал, могу предположить, чтобы сделать демку, как докер работает.

  13. osscombat
    /#22996912

    а в один бинарник через cpython нельзя всё это запихать, вместе с этими requirements.txt?

  14. JleMyP
    /#22997410

    на хабре про упаковку питона в докер написано уже сто тыщ мильенов раз. интереснее было бы почитать про упаковку в snap, flatpack, цельный бинарник и другие форматы, ориентированные на конечного пользователя, а не разраба

  15. Rive
    /#22998794

    Docker, в принципе, замечательная штука, но за пять лет зависимости внутри образа успевают протухнуть, в результате чего приходится разруливать зависимости и пытаться добавить внутрь Dockerfile ключи для репозиториев с истекшим сроком поддержки.