Всем привет! Сегодня хочу поделиться своим подходом к локальной разработке backend‑приложений. Речь пойдёт о том, как вернуться к использованию виртуальных окружений, отказавшись от контейнеризации там, где она скорее мешает, чем помогает.

Каждый разработчик давно знает о преимуществах Docker. Мы привыкли воспринимать его как универсальное решение для любых инфраструктурных задач. Некогда революционная парадигма разработки стала обыденностью и сегодня часто принимается как no‑brainer решение при разработке очередного проекта на локальной машине. Но давайте на минуту остановимся и зададимся вопросом: всегда ли эта избыточная изоляция оправдана? Действительно ли нам нужен «мини‑сервер» на каждом этапе написания кода, или мы просто следуем моде, жертвуя скоростью и комфортом?

Почему мы вообще полюбили Docker (аргументы «за»)

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

  • Идентичность окружений (Dev = Prod). Это «золотой стандарт». Контейнеризация минимизирует риск пресловутого «на моей машине работает, а на сервере — нет». Мы получаем гарантию того, что приложение получит именно те зависимости и системные библиотеки, которые были протестированы и одобрены для эксплуатации.

  • Стерильность хост‑машины. Нам не нужно превращать свою рабочую станцию в «свалку» из разномастных версий Python, Node.js или системных библиотек. Все зависимости живут внутри контейнера, а в системе остаётся только сам Docker.

  • Унификация через IDE. Современные IDE научились «прозрачно» интегрироваться с Docker‑контейнерами. Вы пишете код в привычном интерфейсе, а линтинг, автодополнение и отладка работают внутри изолированного контейнера. Это позволяет вообще не устанавливать интерпретаторы языков напрямую в ОС.

  • Лёгкая оркестрация (Docker Compose). Это, пожалуй, главная киллер‑фича. Одной командой docker-compose up мы поднимаем не только приложение, но и весь сопутствующий стек: базу данных, Redis, очереди сообщений и сторонние API‑заглушки. Такая связность сервисов «из коробки» экономит часы на настройку локальной инфраструктуры.

  • Кроссплатформенность. Docker даёт иллюзию одинакового поведения на Windows, macOS и Linux. Разработчик может сменить ноутбук, но процесс запуска проекта останется прежним.

И как бы красиво всё это ни звучало, на практике всё не так безупречно.

  • Запуск контейнера — операция не самая быстрая. Это не просто «запуск программы», а создание полноценной изолированной среды. Чтобы всё заработало, система должна создать для контейнера виртуальные «стены»: ограничить доступ к файлам, изолировать сетевые порты и виртуализировать системные вызовы ядра. На macOS или Windows это дополнительно требует работы целой виртуальной машины (Docker Desktop), которая эмулирует работу Linux. В результате каждый раз, когда вы «просто запускаете код», ваш компьютер тратит ресурсы на поддержание этой прослойки, упаковку слоёв файловой системы и синхронизацию ресурсов. А с ростом числа проектов, и, соответственно, контейнеров, система становится более медлительной, могут возникать конфликты имён.

  • Также не на всех операционных системах сборки ведут себя одинаково. Иногда приходится компилировать пакеты для совместимости с вашей ОС. Например, на macOS с процессорами Apple Silicon (ARM64) запуск образов, рассчитанных на архитектуру x86_64, требует эмуляции через QEMU. Это не только замедляет запуск, но и часто приводит к проблемам при сборке C‑расширений библиотек: компилятор может пытаться собрать код под целевую архитектуру, не находя нужных системных зависимостей внутри контейнера.

  • Интерпретатор, подключённый из Docker, часто более медленный и ограниченный, а иногда его вообще невозможно настроить под какой‑нибудь старый проект, потому что IDE прекратила поддержку старых версий. Разбираться в ошибках бывает очень утомительно. Вывод журналов в консоль часто менее удобен, могут отсутствовать гиперссылки на фрагменты кода. Нормальная отладка часто либо невозможна, либо сильно ограничена и сопряжена с трудностями (вспомним лаги при индексации файлов).

Какая есть альтернатива

Использовать Docker по его прямому назначению, а именно — для поднятия инфраструктуры (ну и развёртывания в прод, конечно), а разработку самого проекта вести на своей локальной машине. Так, уже более года я использую Docker исключительно как вспомогательный инструмент: для того чтобы поднять локальную базу данных, сторонние back‑to‑back сервисы, брокеры сообщений и так далее. Так как у меня MacOS, мне удобно вести разработку в виртуальном окружении, но с некоторыми нюансами.

Поскольку я работаю над множеством разнородных проектов, мне пришлось решать проблемы с версиями интерпретатора Python и версиями дополнительных пакетных менеджеров.

Для решения первой проблемы на помощь пришёл pyenv. Это очень мощный инструмент, который позволяет держать систему максимально стерильной. У меня даже Python не установлен глобально (если не считать предустановленный unix‑овый 3.10). Я не буду приводить полную инструкцию установки pyenv в систему (можно посмотреть тут), скажу лишь, что делал её с помощью Homebrew.

Далее появляется выбор: используется ли в проекте нестандартный пакетный менеджер?

Если ответ "нет", то развёртываем виртуальное окружение со всеми необходимыми пакетами из requirements.txt и настраиваем интерпретатор в вашей любимой IDE.

Если "да", то также развёртываем виртуальное окружение, а затем уже в него устанавливаем необходимый пакетный менеджер определённой версии. Большинство современных пакетных менеджеров могут работать в рамках уже созданного виртуального окружения и устанавливать все пакеты проекта именно туда.

Вкратце опишу процесс работы с Poetry и UV.

Сначала устанавливаем необходимую для версию Python в pyenv и делаем её локальной:

pyenv install 3.10.13
pyenv local 3.10.13

Создаём виртуальное окружение и обновляем pip:

python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip

Определяем версию пакетного менеджера в проекте и ставим его в наше окружение, а затем устанавливаем зависимости из pyproject.toml или соответствующего лок-файла.

Poetry:

pip install poetry==2.4.1
poetry sync

UV:

pip install uv==0.10.9
uv sync

Советы

Чтобы poetry не создавал своего виртуального окружения внутри вашего (как матрёшка), необходимо запустить команду, которая создаст poetry.toml в корне вашего проекта (можно добавить в .gitignore).

poetry config virtualenvs.create false --local

Для UV достаточно просто назвать ваше виртуальное окружение .venv и он сам определит его как destination для устанавливаемых пакетов.

Выводы

Преимущества подхода:

  • Универсальность: каким бы старым или новым ни был проект, вы сможете его запустить. Мы вручную контролируем всю среду исполнения, собирая её как конструктор.

  • Скорость: проекты будут запускаться быстро, а системные ресурсы использоваться максимально эффективно. Больше никаких поднятий виртуальных ОС, контейнерных IDE helper и прочих ресурсных издержек.

  • Удобство: нативные средства запуска и отладки вашей IDE раскрываются в полную силу. Доступ к стеку вызовов, отслеживание и контроль ресурсов, возможность беспроблемного запуска консольных команд, удобный вывод в консоль и многое другое.

  • Аутентичность: всё, что вам требуется — это ваша IDE и pyenv. Чистая система без глобальных версий и замусоренного Docker — вот он, путь настоящего самурая!

А как вы справляетесь с «зоопарком» зависимостей? До сих пор всё упаковываете в Docker или предпочитаете нативную разработку? Поделитесь своим опытом в комментариях.

Комментарии (56)


  1. DMGarikk
    23.06.2026 08:15

    Подскажите, как сделать несколько venv с разными версиями питона и внутрь ставить пакеты которые не через pip ставятся, а через apt-get (какого вообще черта так устроено?)?

    ах да, я про линукс, вы случайно забыли упомянуть что у вас мак (уже гдето в середине статьи) и там всё выглядит красиво

    ==

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


    1. kgbplus
      23.06.2026 08:15

      1. venv это и есть версия python, каждый раз при создании окружения вы говорите какой интерпретатор (какую версию) использовать.

      2. Все пакеты (мы же про python говорим), которые устанавливаются с помощью apt, можно уставновить с помощью pip. apt просто устанавливает эти пакеты в системное окружение


      1. DMGarikk
        23.06.2026 08:15

        1. Все пакеты (мы же про python говорим), которые устанавливаются с помощью apt, можно уставновить с помощью pip. apt просто устанавливает эти пакеты в системное окружение

        ага, все, а есть psycopg2 например или еще пакеты которые зависят от системных библиотек и вуаля, вы не можете их поставить внутрь venv если у вас сильно различаются версии библиотек


        1. kgbplus
          23.06.2026 08:15

          Вы можете поставить любую библиотеку в venv, просто потому, что виртуальное окружение отличается от системного парой переменных среды и все. Наличие каких то дополнительных зависимостей одинаково влияет на любое окружение, разницы нет.
          Относительно psycopg2 цитата из его документации: "

          For most operating systems, the quickest way to install Psycopg is using the wheel package available on PyPI:

          $ pip install psycopg2-binary

          "


          1. DMGarikk
            23.06.2026 08:15

            For most operating systems, the quickest way to install Psycopg is using the wheel package available on PyPI:

            кроме psycopg еще бывают библиотеки сильно завязанные на ОС, с файловой системой связанные например...правда сейчас уже вылетело из головы название и что мы тогда делали, но сам факт


        1. ya_ne_znau
          23.06.2026 08:15

          Для этого надо прокинуть системные пакеты в виртуальное окружение:

          python -m venv --system-site-packages venv_dir

          Чтобы после этого pip freeze не выплюнул все ваши потроха, можно использовать:

          venv/bin/pip freeze --local


          1. DMGarikk
            23.06.2026 08:15

            всё это прекрасно и замечательно, но както уже не стыкуется с вариантом "venv создает удобное изолированное окружение в два клика"...приходится приседать и извращатся с прокидыванием библиотек, разрешением зависимостей которые при этом вылезают и всякие дополнительные девопс-сложности о которых обычные программисты часто не думают

            а докер, запустил и работает...не там тоже приколы бывают как с альпайном который я тут рядом упоминал и с версиями ядра, но они сильно реже бывают чем прям явный psycopg2 который чутьли не каждый третий использует


            1. kgbplus
              23.06.2026 08:15

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


            1. liquidgel
              23.06.2026 08:15

              приходится приседать и извращатся с прокидыванием библиотек, разрешением зависимостей которые при этом вылезают

              В подавляющем большинстве случаев не надо, у вас нишевый случай


              1. DMGarikk
                23.06.2026 08:15

                нишевой случай - с использованием postgres?


                1. rakhinskiy
                  23.06.2026 08:15

                  Еще есть либы, которые ставятся только через apt или dnf и только в систему, например тот же python3-rpm. Да и случай с postgres мне кажется не нишевый, говорю как тот у кого есть в проде postgres от 12 до 18


                  1. DMGarikk
                    23.06.2026 08:15

                    я к чему и клоню, ситуация очень распространенная, и костыли с пробрасыванием пакетов в venv это вот реально что костыли и художественное раскладывание грабель


    1. garwall
      23.06.2026 08:15

      ну можете посмотреть на conda для такого юзкейса


      1. Kenya-West
        23.06.2026 08:15

        Anaconda нельзя установить с помощью UV, держу в курсе.


        1. garwall
          23.06.2026 08:15

          я в целом вот на это отвечаю
          > внутрь ставить пакеты которые не через pip ставятся, а через apt-get


    1. Verona90210
      23.06.2026 08:15

      Если пакет жестко завязан на системные библиотеки ос, то докер это единственный адекватный вариант не сломать себе хост-систему


  1. akardapolov
    23.06.2026 08:15

    А как вы справляетесь с «зоопарком» зависимостей?

    С помощью Docker и venv (в Python).

    Ваш компьютер тратит ресурсы на поддержание этой прослойки

    Неизбежный компромисс, немного ресурсов взамен удобства работы с «зоопарком» зависимостей и различных ЯП - выгодный обмен.

    упаковку слоёв файловой системы

    Кэшировать все и вся до чего дотягиваются руки (кэш внешних сервисов реестров, например через Nora).

    • на уровне Docker BuildKit через RUN --mount=type=cache;

    • layer cache Docker;

    • каталоги Maven;

    • индекс пакетов apt;

    • deb пакеты.


  1. ic10
    23.06.2026 08:15

    Запуск контейнера — операция не самая быстрая.

    Щито?

    Также не на всех операционных системах сборки ведут себя одинаково. Иногда приходится компилировать пакеты для совместимости с вашей ОС.

    Автор выдает свою вендомакосную боль за общее правило.


    1. DMGarikk
      23.06.2026 08:15

      Автор выдает свою вендомакосную боль за общее правило.

      в линуксе тоже так бывает, если ктото шибко умный решил везде перейти на alpine мотивируя тем что оно легче и народ советовал, при этом совершенно не вникая как оно работает и чем грозит


      1. svl87
        23.06.2026 08:15

        ну погодите, вендомакосная боль в данном контексте это использование VM ради того чтобы запустить контейнер. в случае linux, даже если у вас base layer это alpine с его нетрадиционным libc, то все равно используется host-ядро, новая VM не поднимается, так что в случае с linux-host этой боли нет


        1. DMGarikk
          23.06.2026 08:15

          даже если у вас base layer это alpine с его нетрадиционным libc

          alpine я упомнянул потому что если у вас обычный линукс, а в контейнере alpine - у вас будет пересборка некоторых пакетов с нуля, со всеми потрохами gcc *-headers и т.п. и вылезет проблема с постгрёй которая как раз пересобирается в таком случае...и мы снова имеем странные проблемы с "тормозным никому ненужным докером"


          1. svl87
            23.06.2026 08:15

            ээээ, ну нет же. делается builder-контейнер, в котором стоят все тулы и сборка делается в нем, а не каждый раз ставим gcc и прочее


            1. DMGarikk
              23.06.2026 08:15

              ага, особенно когда вы локально это запускаете

              у меня был мак основным ноутом, я отлично помню что если сбросишь кэш у докера то сборку надо 15 минут ждать потом...потому что "компилится" (с)

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

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


              1. svl87
                23.06.2026 08:15

                билд-контейнеры все равно нужны (как правило), для того же CI например, чтоб он не ставил каждый раз gcc и прочее

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


      1. RTFM13
        23.06.2026 08:15

        Если миллион способов создать себе геморрой в линуксе. Вопрос - зачем ими пользоваться?


    1. Wendor
      23.06.2026 08:15

      Даже скорее боль от разницы архитектур процессоров.

      Я не согласен с первым утверждением, из которого вся боль автора и растет - "Идентичность окружений (Dev = Prod)". Разрабатывая ПО на железе другой архитектуры, не нужно удивляться что работает оно не так же. Так же, архитектура в проде и локально может совершенно отличаться, даже банально из-за количества серверов.

      Для подобных кейсов как у автора придумали всякие docker-compose.override.yml и разные имена docker-compose файлов :). Если надо чтобы работало под arm - надо просто собрать такой образ, в случае если не получается собрать из того же Dockerfile, можно собрать чисто под arm64 и в override указать образ.


    1. Verona90210
      23.06.2026 08:15

      Конечно вендомакосная боль. Настоящие программисты сидят на арче и компилируют ядро перед сном


      1. RTFM13
        23.06.2026 08:15

        Если хотите жить скучно - ставьте дебиан.


      1. ProMix
        23.06.2026 08:15

        *вместо сна


  1. Mr_Boshi
    23.06.2026 08:15

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


    1. DMGarikk
      23.06.2026 08:15

      Сначала локально в виртуальной среде дебажится код,

      дебажить код можно и внутри docker контейнеров, очень кстати удобно для легаси проектов, где версии библиотек и питона могут быть 3-5 летней давности


    1. Phoenix-616
      23.06.2026 08:15

      DevContainers для однородной среды разработки и простоты ее развертывания, TestContainers для однородных интеграционных тестов, Aspire (частично) для локального воспроизведения прод среды и инструментария (поддержка OpenTelemetry – one love). Опять же какая никакая изоляция от атак через зависимости, до хоста из контейнера добраться чуть сложнее, чем просто грепнуть home директорию


    1. MountainGoat
      23.06.2026 08:15

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


    1. RTFM13
      23.06.2026 08:15

      У вас две ветки разработки не совместимых локально. И всё, здравствуй докер.

      До докера для этого были виртуалки. И вот там как раз был жор ресурсов и геморрой с зоопарком. И потом придумали докер и жор ресурсов сократился раз в 10-100.

      А до виртуалок были отдельные физические сервера. Сделал форк - сходил купил сервер. Локальный дебаг? Забудьте.


  1. kalbas
    23.06.2026 08:15

    А как дела с полноценной синхронизацией окружения внутри команды? Надо собрать какой-нибудь PIL, а для него могут быть нужны разные системные пакеты. А если таких реп в работе несколько и в каждой могут быть ньюансы сборки? Там для ML-related вещей тоже такие же проблемки будут, где разные версии базового debian будут давать разный результат, несмотря на одну версию питона.


  1. l1onsun
    23.06.2026 08:15

    А есть ещё такая штука как `nix develop`, которая решает все те же проблемы, которые обычно решают докером, только на голову а то и на две лучше (например по умолчанию окружение там полностью детерминистично в отличии от docker). Но да, порог входа там выше и не без пары ложек дёгтя.


  1. ChillyVanilly
    23.06.2026 08:15

    Смешная статья, в примеры взят кейс который является четким паттерном для использования доцкера.

    При том, что есть реальные антипаттерны в использовании докера. Ну например если ты на java кодишь и у тебя нет зоопарка всякой питоночухни которая ломается при смене минорной версии.


  1. Vasjen
    23.06.2026 08:15

    Что-то вообще не понял, что хотел сказать автор, какую проблему решал вообще, а нейронка еще свои корректировки внесла.

    Зачем вообще разработчику все эти контейнеры при разработке? Ну единичные случаи, это дебаг чего-то конкретного, когда нужно поднять базу, рэббит, каких-то три-четыре сервиса, чтобы они между собой ходили и словить какой-то баг с прода и понять, в чем проблема, если по логам не понятно. Бывают такие случаи, но это скорее 1 на тысячу. В 99 процентов задач вам докер вообще при разработке не нужен вот совсем - проверьте сборку билда, линтеры, тесты как юнит, так и интеграционные. Чем принципиально будет отличать проверка кода через dotnet run и сваггер и работу в поднятом контейнере? Да ничем, собственно.

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

    А как вы справляетесь с «зоопарком» зависимостей? До сих пор всё упаковываете в Docker или предпочитаете нативную разработку? 

    Как вы вообще это в одном месте поставили и сравниваете теплое с мягким? Вот у нас куча приложений от .net 3.1 до 10. Все SDK установлены, нужное подтянется на этапе билда, никаких проблем нет. Возможно в пайтоне какие-то свои приколы, не знаю, тогда извиняюсь, просто как дотнетчику и работающему также под маком вообще не понятна боль и проблема "зоопарка".


    1. xanhex Автор
      23.06.2026 08:15

      Статья про питон разработку на маке, вы приводите аргументы из дот нета, это неконструктивно. Где тут нейронку увидели, тут чисто мой практический опыт описан, такой подход у нас в команде используется и всем это удобно


  1. svl87
    23.06.2026 08:15

    Всё что вы пишите это работает пока вы пишите строго user-land приложения используя исключительно кросс-платформенные инструменты. шаг влево, шаг вправо, например какие-то особые параметры сокета и нативная разработка ломается

    но скажем так, если вы пилите очередной условный интернет-магазин, то да, можно все нативно делать на любой из трех актуальных ОС без докеров


  1. Andrey4ik
    23.06.2026 08:15

    Бред. Вместо того что накатывать uv/poetry/pyenv и вообще пойми что, ставя разные версии питона не понятно куда, потом создавая для них венвы, ты просто создаешь контейнер и прокидываешь volume и тебе вообще плевать что там творится, и почему в данной статье никто не упомянул сервер PostgreSQL, Redis? Их тоже нужно настраивать, а мне впадлу, а на венде это может создать трудности. Правильно подметил чел который вспомнил про psycorg2 тут в комментариях, ну типа, просто зачем мне венвы? Я даже ими не пользуюсь на своем рабочем пк, все скрипты которые лично я пишу для себя юзают глобальное окружение, а для прод/дев - докер


  1. SergeyPerm
    23.06.2026 08:15

    Докер такой хороший, но такой плохой, бла-бла-бла... питон.
    Заголовок не соответствует содержанию.


  1. JBFW
    23.06.2026 08:15

    А что мешает создать 1 (один) раз контейнер докера для разработки того-что-у-вас-там, зайти в него, да и разрабатывать в нем?
    И не удалять потом контейнер, просто затарить готовый проект и выложить куда надо, в такой же контейнер.

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

    Зачем же каждый раз как в первый класс, с нуля запускать...


  1. Elendiar1
    23.06.2026 08:15

    Не вижу смысла вести бекенд разработку на своей хост-машине а не в контейнере. В отличии от любого фронтенда, веба или нативного. Его только локально (из-за скорости, налога на виртуализацию и различия в фс, в контейнере не лучший опыт - горячая перезагрузка не такая отзывчивая и надежная, особенно если dotnet какой то), но и то для него должен быть полноценный докерфайл с compose сервисом для случаев быстрой отладки без необходимости ставить все вручную в ос.


  1. oktobus
    23.06.2026 08:15

    Интересно...


  1. legendasofizma
    23.06.2026 08:15

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


  1. Areso
    23.06.2026 08:15

    Контейнеризация минимизирует риск пресловутого «на моей машине работает, а на сервере — нет»

    Пишу как человек, которому пришлось повоевать с тем, чтобы в OpenShift'e заработали собранные мною контейнеры - нет, ни разу.


    1. Inflame
      23.06.2026 08:15

      В чём проблема была? Такие случаи всё же редкость и являются исключением, а не правилом.


  1. baldr
    23.06.2026 08:15

    Мда, а про безопасность что-то никто не сказал.

    Вот как-нибудь ставите вы новый пакет из NPM / PyPI попробовать, а он слегка заходит в ваши ~/.ssh и бэкапит все ключи в безопасное место..

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


  1. xFFFF
    23.06.2026 08:15

    Когда у тебя пара десятков клиентов, и у каждого свое окружение, то без докера никак.


  1. Verona90210
    23.06.2026 08:15

    Классический холивар

    Истина как обычно посередине: инфраструктуру в докер, код запускать локально