为什么在Apache中嵌入的Python启动时sys.path初始化与从bash运行时不同

1 投票
1 回答
701 浏览
提问于 2025-04-16 18:30

我在用Apache里的Python,使用mod_wsgi这个模块,发现当Apache从rc2.d启动文件夹启动时,sys.path没有正确初始化,而从命令行启动时却没问题。

我的环境版本是:
Ubuntu Lucid 10.04
Apache 2.2
Python 2.6
mod_wsgi 3.3

首先,我用这个应用来测试初始化:

import sys   
import os   
def application(environ, start_response):   
    status = '200 OK'   
    output = ['version %s\n'%sys.version]   
    output.append('sys.prefix = %s \n' % repr(sys.prefix))   
    output.append('sys.exec_prefix = %s \n' % repr(sys.exec_prefix))  
    output.append('sys.path = %s \n' % repr(sys.path))  
    output.append('env.PYTHONHOME = %s\n' % repr(os.environ.get('PYTHONHOME')))
    output.append('env.PATH = %s\n' % repr(os.environ.get('PATH')))
    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(sum([len(o) for o in output])))]
    start_response(status, response_headers)
    return output

当我通过命令行输入'sudo apache2ctl start'或者'sudo /etc/init.d/apache2 start'来启动apache2时,它能正确初始化,应用也能正常显示:

version 2.6.5 (r265:79063, Apr 16 2010, 14:15:55) 
[GCC 4.4.3]
sys.prefix = '/usr' 
sys.exec_prefix = '/usr/local' 
sys.path = ['/usr/local/lib/python2.6/dist-packages/WebOb-1.0.7-py2.6.egg', '/usr/local/lib/python2.6/dist-packages/twiddler-0.9.1-py2.6.egg', '/usr/local/lib/python2.6/dist-packages/elementtree-1.2.7_20070827_preview-py2.6.egg', '/usr/local/lib/python2.6/dist-packages/lxml-2.3-py2.6-linux-x86_64.egg', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old', '/usr/local/lib/python2.6/lib-dynload', '/usr/lib/python2.6/dist-packages', '/usr/lib/pymodules/python2.6', '/usr/local/lib/python2.6/dist-packages', '/usr/local/lib/python2.6/dist-packages'] 
env.PYTHONHOME = '/usr:/usr/local'
env.PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin'

但是,当apache2从/etc/rc2.d在启动时启动时,它就不能正确初始化,应用显示:

version 2.6.5 (r265:79063, Apr 16 2010, 14:15:55) 
[GCC 4.4.3]
sys.prefix = '/usr' 
sys.exec_prefix = '/usr/local' 
sys.path = ['/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old', '/usr/local/lib/python2.6/lib-dynload'] 
env.PYTHONHOME = '/usr:/usr/local'
env.PATH = '/sbin:/usr/sbin:/bin:/usr/bin'

一些重要的目录找不到,包括dist-packages。

我尝试把apache的启动脚本在启动顺序中提前或推后,但结果都不好。把apache放在最后启动时,sys.path就出问题;而从命令行立即启动时,sys.path就正常。

问题是,为什么sys.path在作为启动进程运行时和从命令行运行时初始化会不一样呢?

后续情况:

Python的初始化没有运行site.py。我现在看到mod_wsgi报错“无法导入'site'模块”。这个错误是在我在Apache2.conf中设置了WSGIPythonPath值后出现的,虽然sys.path的问题一直存在。

看起来是chroot Apache和从rc#.d脚本启动的组合导致Python的site.py加载出现了问题。

从命令行用sudo或者sudo -i从一个全新的账户启动Apache是没问题的。

1 个回答

0

你现在是以不同的用户身份在运行程序。Bash(还有其他登录脚本)在你以普通用户身份登录时,会设置一些路径变量,但当你以apache用户身份启动时,这些变量可能就没有被设置。

Apache的初始化是正确的。你只需要明确告诉它你想要包含哪些路径,如果你需要的话。

这和你在运行定时任务时常常需要更明确的设置是一个道理。

当你使用sudo命令切换到那个用户时,你的一部分环境变量会保留,包括你的python路径变量。如果你想模拟root用户最初登录并运行apache时的情况,你需要在sudo命令后加上-i选项。

http://www.gratisoft.us/sudo/man/1.8.0/sudo.man.html#i_command

撰写回答