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.