Pull to refresh

Comments 9

воспроизводимое окружение

...попытаться получить актуальный список зеркал Arch Linux для нужного региона и использовать их для установки пакетов. Делается несколько попыток с таймаутами и ретраями, потому что archlinux.org время от времени бывает недоступен 

...Дальше обновляем систему (у нас rolling-release!)

точно воспроизводимое?

postgresql-libs mariadb-libs

прям две субд сразу используете в проде?

Дополнительно убираем sudo, так как в production-образе он не нужен

а зачем ставили?

точно воспроизводимое?

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

прям две субд сразу используете в проде?

Это пример установки библиотек в шаблоне. Эти библиотеки вообще можно убрать из .env если python пакеты не имеют от них зависимостей. На практике DS/ML проекты не обходятся без клиентов к БД, поэтому решил оставить для иллюстрации.

а зачем ставили?

sudo остаётся для dev сборок. Иногда по зависитям что то не работает сразу. Удобно в контейнере что то доставить, проверить и потом перенести решение в сборки за один раз.

Как вы планируете решать недоступность archlinux.org в случаях когда домашний провайдер ограничивает доступ к нему потому что Роскомнадзор?

Это если что не выдуманный пример, ресурсы Арча сидят на инфраструктуре Хецнера, к которой в том или ином виде еще год назад Дом.ру ограничивал доступ.

Если честно, то я пока ни разу не сталкивался с блокировкой хостинга archlinux.org со стороны своего провайдера (РТ). Но, конечно же, такое может случиться.

Если запрос зеркал не отработает, то в контейнере остануться зеркала по умолчанию. Сейчас это:

Server = https://fastly.mirror.pkgbuild.com/repo/os/arch
Server = https://geo.mirror.pkgbuild.com/repo/os/arch

По whois, похоже, это один и тот же провайдер.

В качестве решения можно задать зеркала в отдельном конфиге (например, зеркало Яндекса). И на сборке заменять /etc/pacman.d/mirrorlist без динамического резолвинга зеркал по стране. В этом случае, докерфайл получится короче, но нужно следить за актуальносью зеркал.

Зачем внутри контейнера нужен venv, это и так изолированная среда?

Зачем копировать src до вызова установки зависимостей, это решение приводит к тому что любое изменение кода приводит к необходимости пересобирать слой, вместо того чтобы взять слой с уже установленными зависимостями? Для ci пайплайнов такие упущения ведут к долгим пересборкам контейнеров, а они по хорошему не должны занимать дольше пары минут (нужно максимально использовать кеш слоев и кеш самого poetry).

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

Зачем внутри контейнера нужен venv, это и так изолированная среда?

Хорший вопрос. Могу поделиться интуицией. venv здесь используется не для изоляции, а для структуры и предсказуемости. venv вместе с целевой версией питона выделяет окружение проекта в отдельный, хорошо определённый слой. Это упрощает контроль зависимостей, хорошо интегрируется с poetry и делает поведение окружения более стабильным в мультистадиных сборках. В таком подходе зависимости проекта не смешиваются с системным питоном и не протекают между стадиями сборки.

Кроме того, на практике многие инструменты, типа, линтеры, чекеры, форматтеры и автокомплитеры (black, pylint, ruff, lsp и т. д.) ожидают наличие виртуального окружения или, по крайней мере, работают с ним более предсказуемо.

Зачем копировать src до вызова установки зависимостей

poetry install в режиме установки root пакета требует наличия readme и исходного кода проекта. Поэтому на этом этапе код копируется заранее. Подумаю как разделить, но вызовов poetry install будет два...

Снятие лимитов тоже крайне сомнительная история

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

В таком подходе зависимости проекта не смешиваются с системным питоном и не протекают между стадиями сборки.

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

Кроме того, на практике многие инструменты, типа, линтеры, чекеры, форматтеры и автокомплитеры (black, pylint, ruff, lsp и т. д.) ожидают наличие виртуального окружения или, по крайней мере, работают с ним более предсказуемо.

Я не очень понимаю зачем всё это нужно в контейнере. В всяком случае этого точно не должно быть в prod контейнере. По моему мнению, все это должно быть на рабочем месте у разраба а не в контейнере. По хорошему контейнер должен содержать только то что необходимо для работы приложения, а именно - код и установленные зависимости. Без изменения зависимостей сборка контейнера может укладываться в один вызов copy, что очень быстро.

poetry install в режиме установки root пакета требует наличия readme и исходного кода проекта.

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

Давайте я немного поясню контекст, в котором я с этим сталкиваюсь на практике.

В DS/ML проектах зависимости обычно тяжёлые, чувствительные к версии окружения и легко могут занимать 5+ ГБ (только py пакеты). При этом код должен одинаково запускаться локально, на удалённых dev боксах и, условно, в k8s кластере. Да, разработчик может самостоятельно поставить себе venv, настроить питон, зависимости, линтеры и редактор. Но на практике это почти всегда означает часы ручной настройки, расхождения окружений и ошибки, которые сложно воспроизводить.

В этом шаблоне делается другой выбор: разработчику сразу даётся готовый dev инструмент, который поднимается одной командой docker compose run. В моём случае это слой с vim/jupyter/codex..., но это не принципиально, т.к. на его месте может быть VS Code devcontainer или любая другая IDE. Ключевая идея в том, что редактор и инструменты работают в том же окружении, где живёт код и зависимости, локально или на удалённой машине, в том числе с доступом к GPU.

При этом важно разделять dev и прод контейнеры, и в шаблоне это разделение есть. В прод образе (или заготовке под него) нет линтеров и прочих dev инструментов, там только код и runtime зависимости. Реализовать это можно разными способами, я выбрал установку через poetry с группами зависимостей для унификации подхода.

Согласен, у такого решения есть избыточность по размеру dev образов. В общем случае, CI и прод сборки почти всегда требуют отдельной оптимизации и универсального решения здесь не существует. Однако, процедура настройки рабочего окружения сводится к паре команд, а довести шаблон до конкретных прод сценариев можно в любой момент, уже под задачи проекта.

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

Спасибо что поделились опытом.

Sign up to leave a comment.

Articles