我正在运行一个 uwsgi Emperor,其中包含各种 Vassal,每个 Vassal 都从不同的虚拟环境为特定的 Python 应用程序提供服务。由于 uwsgi 是使用其自己的 Python 2.7 解释器编译的,因此尝试使用包含 Python 3 的虚拟环境会在 vassal.log 中产生以下错误:
ImportError: No module named site
我认为此错误的根源在于 uwsgi 使用其内置的 Python 2.7 解释器,而它运行的虚拟环境目录仅支持 Python 3 解释器。事实上,当我使用另一个 uwsgi(只需在pip install uwsgi
同一个虚拟环境中安装它)时,错误就会消失。但是,我希望一个 Emperor 可以统治几个不同的虚拟环境,因此在每个虚拟环境中安装单独的 uwsgi 不是一个选择。
根据这个答案在 Stackoverflow 上,解决这个问题的正确方法是使用不同的 Python 解释器将 uwsgi 编译为可加载模块。在我采用这种方法之前,我想知道如何配置我的 Vassals 以分别使用另一个解释器插件。
现在我有一个从我的 /etc/rc.local 启动的 Emperor,其设置如下:
[uwsgi]
uid = www-data
gid = www-data
master = true
emperor = /etc/uwsgi/vassals
daemonize = /var/log/uwsgi/emperor.log
然后我有一堆带有如下ini文件的Vassals:
[uwsgi]
master = false
single-interpreter = true
socket = /tmp/%n.sock
virtualenv = /home/user/.virtualenvs/djangoproject
chdir = /home/user/djangoproject
wsgi-file = project/wsgi.py
logto = /var/log/uwsgi/%n.log
我用几个解释器插件编译一个调整过的 uwsgi 版本没有问题,但我想知道我需要在我的配置中做哪些改变才能真正使用这些单独的解释器。我只能说一个vassal.ini:
plugin = python3.4
另一则消息:
plugin = python2.7
?
请帮我弄清楚如何在同一个 uwsgi Emperor 下结合 Python 2.7 和 Python 3 virtualenvs。
答案1
好吧,因为我并没有被这些回复所淹没,所以我自己想出了以下解决方案:
首先,我使用 Python 3 解释器创建了一个新的虚拟环境:
mkvirtualenv -p /usr/bin/python3 python3env
然后我从 Pypi 安装了常用的 uwsgi,它会使用 Python 3 解释器自动编译:
pip install uwsgi
我创建了一个包含 Emperor.ini 的配置目录/etc/uwsgi-python3
和一个包含 vassal.ini 的子目录 vassals。最后,我将以下行添加到/etc/rc.local
/home/user/.virtualenvs/python3env/bin/uwsgi --ini /etc/uwsgi-python3/emperor.ini
现在有一个 uwsgi Emperor 正在运行,它使用 Python 3 解释器作为其 vassal。它不会干扰另一个已在运行并使用 Python 2.7 解释器的 uwsgi Emperor。
我知道这不是最佳选择,因为我没有使用可插入式解释器架构在文档中解释(感谢 roberto!我不知道我怎么会忽略了这一点)。但是,它运行完美,我不需要触碰为大量生产应用程序提供服务的现有 uwsgi 安装。
答案2
在 osx 下我这样做了。我卸载了系统上的所有 uwsgi(从 brew 到 pip 等)。
之后我下载了/usr/local下的源代码
wget https://projects.unbit.it/downloads/uwsgi-latest.tar.gz
tar zxvf uwsgi-latest.tar.gz
后
cd uwsgi-2.0.17
make PROFILE=nolang
通过这种方式,我创建了一个没有 Python 插件的可执行文件。
之后我为系统上的每个版本制作了每个插件:
PYTHON=python3.6 ./uwsgi --build-plugin "plugins/python python36"
PYTHON=python2.7 ./uwsgi --build-plugin "plugins/python python27"
PYTHON=python2.6 ./uwsgi --build-plugin "plugins/python python26"
现在我有 3 个插件。
在我的 Emperor 的 ini 文件中,我为每个文件指定了插件目录和插件版本
[uwsgi]
plugins-dir = /usr/local/uwsgi-2.0.17
plugin = python36
[uwsgi]
plugins-dir = /usr/local/uwsgi-2.0.17
plugin = python27
[uwsgi]
plugins-dir = /usr/local/uwsgi-2.0.17
plugin = python26
...
我在 /usr/local 文件夹中对 uwsgi 二进制文件进行了符号链接
ln -s /usr/local/uwsgi-2.0.17/uwsgi /usr/local/bin/uwsgi
然后皇帝就跑了
uwsgi --emperor /PATH/TO/INI/FILES/FOLDER/
现在我可以同时运行 python26、python27 和 python36 项目了
答案3
另一个可能的解决方案是重用系统范围的“emporor”,只用新版本替换 vassal。这样,您无需在 下创建任何新文件夹,/etc
也无需向 启动新服务rc.local
。
uwsgi
通过安装pip
到虚拟环境中。编辑
/etc/uwsgi/apps-enabled/your-app.ini
如下:- 删除该
plugins=...
行(因为 pip-compileduwsgi
不支持插件)。 添加以下行:
unprivileged-binary-patch = /path/to/your/venv/bin/uwsgi
这将强制 uWSGI Emperor
uwsgi
以附庸身份启动你自己的二进制文件。
- 删除该
在 Emperor 中重新加载您的应用程序
service uwsgi restart your-app
。
最后一步不知为何报告重新启动服务器失败:
* Starting app server(s) uwsgi
...fail!
但实际上,新的 vassal 和所有其他应用程序一样启动正常。我没有时间调试它。