2025, Nov 10 18:02

Как установить sdist без компиляции: собираем wheels на build-машине и ставим на продакшене

Решение для pip, когда на PyPI только sdist: заранее собрать wheels на build-машине, перенести на продакшен и установить локально без компиляции и сети.

Когда производственный хост не может собирать из исходников, а нужный пакет на PyPI доступен только как sdist, привычный рабочий процесс с pip дает сбой. Это часто случается при разделении ролей: есть «build»-машина с полным набором инструментов и «production»-машина, где оставлено лишь самое необходимое. Даже если обе системы совпадают по архитектуре, дистрибутиву Linux и PyPy, установленному через pyenv, отсутствие сборочных зависимостей на продакшене заблокирует установку.

Problem

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

python -m pip install sample-lib

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

What’s actually going wrong

Корень проблемы не в pip и не в Python, а в отсутствии сборочных зависимостей на продакшене. Когда на PyPI нет готового колеса (wheel), pip откатывается к компиляции sdist — это выполнимо на build‑машине, но непрактично на production. Нужен способ использовать то, что уже может собрать build‑хост, и полностью избежать компиляции на целевой системе.

Solution: pre-build wheels offline and install locally

Обходной путь такой: на сборочной машине скачать всё необходимое и превратить любые архивы исходников в колёса, затем скопировать результат на продакшен и установить из локальных файлов. Начните с загрузки пакета и его зависимостей на build‑хост в отдельный каталог:

python -m pip download sample-lib -d ./wheelstash

Эта команда сложит рядом и колёса, и исходные архивы. Если какие‑то файлы пришли как .tar.gz, преобразуйте их в колёса, чтобы на продакшене не понадобилась сборка:

python -m pip wheel --no-deps --wheel-dir=./wheelstash ./wheelstash/*.tar.gz

Перенесите весь каталог wheelstash на производственную машину привычным способом. Затем установите пакет из локального пути, не обращаясь к PyPI:

python -m pip install --no-index --find-links=./wheelstash sample-lib

Если ваш процесс упаковки этого требует, могут понадобиться также setuptools и wheel. Подробности по команде download смотрите здесь: https://pip.pypa.io/en/latest/cli/pip_download/.

Why this matters

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

Conclusion

Если на PyPI нет готового колеса, используйте контролируемый конвейер сборки: скачайте на подходящей машине, преобразуйте sdist в колёса и устанавливайте на продакшене из локального каталога с колёсами. Следите, чтобы обе среды совпадали по архитектуре и версии Python, кешируйте полученные артефакты и отдавайте предпочтение локальной установке с ключами --no-index и --find-links — так развёртывание остаётся воспроизводимым и безопасным.

Статья основана на вопросе со StackOverflow от mysteryegg и ответе Viktor Sbruev.