3 月份搭建的 python web 框架,在一个项目中落地后,在部署的时候还是稍显麻烦,虽然用了 pipenv 的方式管理依赖,但是在线上的时候还得要求线上环境可以连外网,但是一般线上环境会有一些隔离,而且上线前也会有一些 python 依赖要去安装,这其实还不够极致。所以需要一种能把 python 项目打成 bin 文件的方式,所有依赖的包都集成在这个 bin 文件中,直接上线 bin 文件就可以了。如果这个能实现其实就解决了目前我的需求了。
带着这个出发点就去找解决方法,工具其实挺多,我选择了 pyinstaller 这个工具作为第一个尝试目标。
环境特点:首先我们用的 pipenv 管理应用的,每个应用其实都有一套独立的虚拟环境,所以这个时候 pyinstaller 不能安装到全局,我刚开始使用的 pip3 去安装到了全局,然后用 pyinstaller 命令去打包项目,发现使用 pipenv 管理的包不能被打包 bin 文件里面去,运行的时候就报依赖包缺失。所以一定要用 pipenv install -d pyinstaller 去安装到项目的虚拟环境中。
见文章:pipenv and pyinstaller not packaging dependencies
但是解决上面依赖没进 bin 文件的问题后,我们打完的 bin 文件运行的时候仍然报了如下的错
➜ test git:(master) ✗ ./dist/test
Traceback (most recent call last):
File "main.py", line 1, in <module>
from sanic import Sanic
File "/Users/doctorq/.local/share/virtualenvs/test-o9LtdYv1/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "site-packages/sanic/__init__.py", line 1, in <module>
File "/Users/doctorq/.local/share/virtualenvs/test-o9LtdYv1/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "site-packages/sanic/app.py", line 19, in <module>
File "/Users/doctorq/.local/share/virtualenvs/test-o9LtdYv1/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 627, in exec_module
exec(bytecode, module.__dict__)
File "site-packages/sanic/config.py", line 4, in <module>
ModuleNotFoundError: No module named 'distutils'
[84155] Failed to execute script main
缺少 distutils,这个问题折腾了两天,总算找到解决方法,见文章:distutils not included with latest virtualenv,具体解决方法就是修改你虚拟环境下的PyInstaller/hooks/pre_find_module_path/hook-distutils.py,然后打包的就没问题了。
最后给出打包命令:pipenv run pyinstaller -F main.py -n test
不更,这种需要每次都手动更改的方式,暂时不推广,太恶心。等啥时候 pyinstaller 修复这个问题,再说吧,但至少 pyinstaller 打 bin 包的方式还是可行的~暂时还用源码部署着吧