apache部署多个互相依赖的项目
项目中需要将多个 Django 项目需要部署在同一个 Apache2 的 VirtualHost 下面。却碰到了一个棘手的问题,就是发现这些 Django 项目共用了一个 Python 运行环境。先来看我的配置文件:
<VirtualHost *:80> WSGIScriptAlias /a /path/to/project/a.wsgi WSGIScriptAlias /b /path/to/project/b.wsgi </VirtualHost>
看起来很简洁明了。即 VirtualHost *:80 的 /a 路径指向 a 项目,/b 路径指向 b 项目。
但是实际运行的时候问题来了:
apache 报 500 错误,看 /var/log/apache2/erro.log 发现有如下错误:
[Mon Aug 06 17:30:47 2012] [error] [client ::1] mod_wsgi (pid=12294): Exception occurred processing WSGI script '/path/to/project/a.wsgi'. [Mon Aug 06 17:30:47 2012] [error] [client ::1] Traceback (most recent call last): [Mon Aug 06 17:30:47 2012] [error] [client ::1] File "/usr/local/lib/python2.6/dist-packages/Django-1.4.1-py2.6.egg/django/core/handlers/wsgi.py", line 219, in __call__ [Mon Aug 06 17:30:47 2012] [error] [client ::1] self.load_middleware() [Mon Aug 06 17:30:47 2012] [error] [client ::1] File "/usr/local/lib/python2.6/dist-packages/Django-1.4.1-py2.6.egg/django/core/handlers/base.py", line 39, in load_middleware [Mon Aug 06 17:30:47 2012] [error] [client ::1] for middleware_path in settings.MIDDLEWARE_CLASSES: [Mon Aug 06 17:30:47 2012] [error] [client ::1] File "/usr/local/lib/python2.6/dist-packages/Django-1.4.1-py2.6.egg/django/utils/functional.py", line 184, in inner [Mon Aug 06 17:30:47 2012] [error] [client ::1] self._setup() [Mon Aug 06 17:30:47 2012] [error] [client ::1] File "/usr/local/lib/python2.6/dist-packages/Django-1.4.1-py2.6.egg/django/conf/__init__.py", line 42, in _setup [Mon Aug 06 17:30:47 2012] [error] [client ::1] self._wrapped = Settings(settings_module) [Mon Aug 06 17:30:47 2012] [error] [client ::1] File "/usr/local/lib/python2.6/dist-packages/Django-1.4.1-py2.6.egg/django/conf/__init__.py", line 95, in __init__ [Mon Aug 06 17:30:47 2012] [error] [client ::1] raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e)) [Mon Aug 06 17:30:47 2012] [error] [client ::1] ImportError: Could not import settings 'b.settings' (Is it on sys.path?): No module named b.settings
很明显,a 项目的 wsgi 程序在找 b 项目的 settings 模块。正常情况下,a 项目的 wsgi 程序找的应该是 a 项目的 settings 模块,而 b 项目的 wsgi 程序找的也应该是 b 项目的 settings 模块。
这里为什么会错了呢?
再看 a 项目的 wsgi 程序代码 (b 也一样):
import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "a.settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application()
可以看出在一开始,设置了一个叫 DJANGO_SETTINGS_MODULE 的环境变量,b 项目设的是 b.settings。 从上面 apache 的 error log 中可以看出两个不相干的项目在找对方的 settings 模块。因此猜测是两个 wsgi 进程共用了一个 python 运行环境,导致后执行的 b 程序重写了 a 程序的 DJANGO_SETTINGS_MODULE 环境变量。因此下一次请求来的时候,a 项目按变量中的设置去找了 b 项目中的模块。
猜测了原因后开始对症下药,发现 mod_wsgi 有一个 process group 的概念。用不同的 process group 把不同的 django 项目运行环境分开即可。
配置方法如下:
<VirtualHost *:80> WSGIDaemonProcess a processes=2 threads=5 WSGIDaemonProcess b processes=2 threads=5 WSGIScriptAlias /a '/path/to/project/a.wsgi' WSGIScriptAlias /b '/path/to/project/g.wsgi' <Location /a> WSGIProcessGroup a WSGIApplicationGroup %{GLOBAL} </Location> <Location /b> WSGIProcessGroup b WSGIApplicationGroup %{GLOBAL} </Location> </VirtualHost>
简单地解释下,大概就是建立两个 WSGIDaemonProcess,a 和 b。然后指定 a 项目用 a 这个 Group,b 项目用 b 这个 Group,大家就互不相干了。
Update:
在最新的项目中,发现这样也会出现问题,两个环境还是会混淆,于是又加了一层保险,把两个项目的 settings 环境变量的名字给改了,改完后 wsgi.py 文件变成这样(project b 也同样地改):
import os import site import django.conf django.conf.ENVIRONMENT_VARIABLE = 'DJANGO_A_SETTINGS_MODULE' os.environ.setdefault('DJANGO_A_SETTINGS_MODULE', 'project_a.settings') from django.core.handlers.wsgi import WSGIHandler application = WSGIHandler()