最近,州的先生在对 MrDoc 专业版(一个基于 Django 开发的在线文档系统)进行最后的上线测试工作。
原本在开发环境下测试得好好的「一键更新」功能,在宝塔面板上通过 uWSGI 部署之后,突然不能使用了。
期间各种搜索、改代码、测试,简直快要崩溃,幸运的是,最终问题得以解决,下面回顾一下这些问题及其解决方法,方便大家借鉴和避坑。
开发环境:
测试环境:
在 Django 内通过 subprocess.Popen() 方法,调用系统命令,拉取最新的 Git 仓库代码,然后执行 Django 的数据迁移命令,最后执行 pip 命令更新项目依赖库。
在原代码中,已经对 subprocess.Popen() 方法进行了一定的优化和处理。
首先,通过cwd参数指定命令运行的路径,通过stdin、stderr、stdout参数获取命令执行的输出内容,通过communicate()等待命令执行完成。
最终的脚本调用代码如下所示:
Popen(
[python_env, 'manage.py', 'makemigrations'],
stdin=PIPE,
stderr=PIPE,
stdout=PIPE,
cwd=settings.BASE_DIR
)
out_2, err_2 = mig_call.communicate()
最开始出现的是 Git 认证问题。
仓库的代码通过 https 的方式进行拉取:
git clone https://git.mrdoc.pro/MrDoc/MrDocPro.git
正常情况下,在命令行终端输入 git 相关命令可以直接进行操作。
但是日志里面却报出了一个错误:
fatal: could not read Username for 'https://git.mrdoc.pro'
试过使用:
git config --global credential.helper store
这在命令行界面启动 uWSGI 时运行没问题:
uwsgi --ini uwsgi.ini
但是一旦使用宝塔面板的「Python 项目管理器」启动,就会继续报上述错误:

最后通过修改 git 仓库地址,在地址上附带用户名和密码得以解决:
git clone https://{username}:{password}@git.mrdoc.pro/MrDoc/MrDocPro.git
因为需要执行 Django 的数据迁移命令,所以需要在脚本中调用Python:
python manage.py migrate
这在单一的 Python 环境下,也是没有任何问题的。但是在 Linux 上,在虚拟环境中,这个问题就凸现出来了。
首先很多服务器使用的 Linux 还是自带了 Python2,且默认的python命令指向的也是 Python 2,就算将其指向到 Python3。
其次,全局 Python 的第三方模块和虚拟环境内的第三方模块也不一样。
为了让代码里面执行的python命令指向正确的 Python 解释器路径,州的先生使用了 Python 内置库 sys提供的executable属性,这个属性会返回 Python 解释器的可执行二进制文件的绝对路径。
例如:

虚拟环境中:

按理来说,用 sys.executable 代替python是不会错的了,结果又报出个错误来:
unable to load configuration from manage.py
网上搜索不到合适的问题,只得自己调试,在代码中把 sys.executable 的值打印出来,才发现 sys.executable 指向了 虚拟环境内 uWSGI 的路径。
借着这一关键信息搜索,才发现这一问题在 2014年就已经存在:

而开发者的解释是:
uwsgi 就是当前的 python 解释器,因为它链接 libpython.so。获取 sys.executable 是不可能的,因为库本身没有硬编码的二进制路径。
好吧。知道原因就好办了。虚拟环境内的 uWSGI 一般都存在于虚拟环境python的同级目录,在调用 sys.executable 之前对其返回值进行一下判断。
如果值以uwsgi结尾,就可以将其替换掉,如果是正常的Python解释器路径,就可以直接使用。
当问题解决了,回想起来,好像解决方法也是很简单。
这关键在于,出现问题后,要及时定位到问题点所在。
如果不知道问题点所在,就只能盲目地找答案,而这,往往是找不到答案的。
解决问题的方法可能很简单,但是如果找不到问题点,再简单的解决方法可能也不会被自己注意到,最终就像电视剧里面的两个人,那么近又那么远,最终擦肩而过。
🧐分享、点赞、在看,避免更多的人踩坑!👇