使用pyenv和virtualenv在apache后面部署flask应用程序时找不到numpy,pandas模块

Posted

技术标签:

【中文标题】使用pyenv和virtualenv在apache后面部署flask应用程序时找不到numpy,pandas模块【英文标题】:numpy, pandas modules not found when deploying flask app behind apache with pyenv and virtualenv 【发布时间】:2017-12-07 04:09:49 【问题描述】:

我为一个相当详细的应用程序构建了一个烧瓶前端,经过大量编码后,它在本地完美运行。所以现在我想让它对公众可见,所以已经读过它需要一个 apache 或 nginx 前端。我计算出我需要的实例大小并在 AWS 上将其打开,并运行了 these 两个 tutorials,这证明基本情况是有效的。 Apache 设置完成后,当我导航到 AWS 实例的 IP 时,会显示 Apache 欢迎页面。然后,当我暂时将“Hello World”代码替换为我的烧瓶应用程序并使用 IP 刷新浏览器时,hello world 出现了。此外,如果我用 here 替换 flasskapp.py 代码,它可以完美地跨 apache 提供输入到浏览器中的 IP 由 pip 找到的模块列表,包括 Numpy 和 Pandas,否则它会抱怨找不到!但是,可以通过在顶部添加 import numpy 轻松杀死此脚本,但它给了我以下错误消息:

ImportError: cannot import name 'multiarray'

Importing the multiarray numpy extension module failed.  Most
likely you are trying to import a failed build of numpy.
If you're working with a numpy git repo, try `git clean -xdf` 
(removes all files not under version control).  
Otherwise reinstall numpy.

都在 apache 日志中。

当我放回我的应用程序而不是 hello world 时,就会出现问题。它只是拒绝导入 pandas,这是 Apache 日志的最后一部分:

Mon Jul 03 19:42:14.691081 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560] Traceback (most recent call last):
[Mon Jul 03 19:42:14.691126 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]   File "/var/www/html/flaskapp/flaskapp.wsgi", line 30, in <module>
[Mon Jul 03 19:42:14.691130 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]     from similar_items_frontend import app as application
[Mon Jul 03 19:42:14.691137 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]   File "/var/www/html/flaskapp/similar_items_frontend.py", line 4, in <module>
[Mon Jul 03 19:42:14.691140 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]     from item_similar_to_doc import similar_to_doc
[Mon Jul 03 19:42:14.691145 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]   File "/home/ubuntu/find-similar/frontend/../item_similar_to_doc.py", line 1, in <module>
[Mon Jul 03 19:42:14.691148 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]     from PullVectors import p
[Mon Jul 03 19:42:14.691153 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]   File "/home/ubuntu/find-similar/frontend/../RunSimilarity.py", line 5, in <module>
[Mon Jul 03 19:42:14.691156 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]     import pandas as pd
[Mon Jul 03 19:42:14.691161 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]   File "/home/ubuntu/.pyenv/versions/miniconda3-latest/envs/find_similarProject/lib/python3.6/site-packages/pandas/__init__.py", line 19, in <module>
[Mon Jul 03 19:42:14.691164 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560]     "Missing required dependencies 0".format(missing_dependencies))
[Mon Jul 03 19:42:14.691180 2017] [wsgi:error] [pid 12300:tid 140131159766784] [client 93.21.05.132:52560] ImportError: Missing required dependencies ['numpy']

我觉得我什么都试过了

这里是000-default.conf

WSGIPythonPath /home/ubuntu/.pyenv/versions/miniconda3-latest/envs/vtenv4YTproject/lib/python3.6/site-packages/

<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        WSGIDaemonProcess flaskapp threads=5
        WSGIScriptAlias / /var/www/html/flaskapp/flaskapp.wsgi

        <Directory flaskapp>
              WSGIScriptReloading On
              WSGIProcessGroup %GLOBAL
              WSGIApplicationGroup %GLOBAL
              Order allow,deny
              Allow from all
        </Directory>



        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog $APACHE_LOG_DIR/error.log
        CustomLog $APACHE_LOG_DIR/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

我应该提一下,当我通过 ssh 进入 AWS 实例时,我的烧瓶应用程序在其 virtualenv 中完美运行(直到烧瓶为页面提供服务),当然要让它工作有点修修补补,但它找到它的所有依赖项,而不是在 pandas 导入时崩溃。

为了尝试修复它,我查看了 here、here,添加了来自 here 的一些代码,查看了大量文档 here,我的 flaskapp.wsgi 文件如下所示:

import sys
import logging
import os.path
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
import config
import site

prev_sys_path = list(sys.path) 

site.addsitedir('/home/ubuntu/.pyenv/versions/miniconda3-latest/envs/find_similarProject/lib/python3.6/site-packages')

new_sys_path = []

for item in list(sys.path): 
    if item not in prev_sys_path:
        new_sys_path.append(item) 
        sys.path.remove(item)
sys.path[:0] = new_sys_path 

logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/var/www/html/flaskapp")

from similar_vids_frontend import app as application
application.secret_key = config.WSGI_KEY

我没有理由找到为什么 pandas / numpy 导入在 apache 上失败但在 virtualenv 中运行时工作正常。根据文档,我想知道是否与权限和组有关:

请注意,Apache 运行您的代码的用户需要能够访问 Python 虚拟环境。在某些 Linux 发行版上,其他用户无法访问用户帐户的主目录。与其更改主目录的权限,不如考虑将 WSGI 应用程序代码和任何 Python 虚拟环境放在主目录之外。

但是 Ubuntu 是 那些 发行版之一,然后将虚拟环境和项目安装到 / 文件夹中?

感谢任何提示或解决方案。

【问题讨论】:

this question 对您有帮助吗? 谢谢。我看到了,但不知道“守护程序模式”是什么或我是否正在使用它。我开始认为是我在使用github.com/pyenv/pyenv-virtualenv,但实际上并没有使用sudo apt install virtualenv,尽管一切都在运行,除非 apache 尝试运行它 您正在使用WSGIDaemonProcess,所以我认为您确实在使用答案所说的守护进程模式。您是否尝试过答案建议的解决方法? WSGIProcessGroup 的值应该与WSGIDaemonProcess 指令的名称相匹配。另一篇文章是关于 WSGIApplicationGroup 的,但不同。 Python 3.6 工作正常,但 mod_wsgi 必须已为其编译。您不能像我之前所说的那样尝试强制为 3.5 编译的 mod_wsgi 使用用 3.6 创建的虚拟环境。使用modwsgi.readthedocs.io/en/develop/user-guides/… 中的过程来验证您的 mod_wsgi 是如何构建的。 【参考方案1】:

这现在有效,主要归功于 Graham 的配方 here 和 this answer 关于将模块加载到 apache 中的方法。它有效的证明是 hello world 应用程序的以下变体:

from flask import Flask
import numpy
app = Flask(__name__)

@app.route('/')
def hello_from_np():
  a = numpy.array([4,5,6])
  return str(a)

if __name__ == '__main__':
  app.run()

当您转到 IP 时,在浏览器中为您提供此信息:

...而不是 apache 日志中关于 numpy 的一堆错误。 这一切都是为 Python 3.6 设置的:

AH00489: Apache/2.4.7 (Ubuntu) mod_wsgi/4.5.15 Python/3.6 configured

想记录一些细节作为给自己的便条,以防万一有人遇到麻烦并试图重现这一点,也许可以让你免于找错树的日子。..

所以我从 Ubuntu Server 16.04 切换到 14.04.5 LTS,以防万一这是问题的一部分,也因为 pyenv 性能不佳,在安装我正在测试的许多旧 Python 版本的过程中崩溃。还选择省略 pyenv-virtualenv,因为没有为此实例计划多个项目,而且出错的事情更少。

从 Ubuntu 的全新安装中,除了安装 apache2、pyenv、libapache2-mod-wsgi,用 a2enmod 激活它之外,我特意在用 pip 安装要求之前运行了以下几行,其中包括 numpy,所以它没有抱怨:

sudo apt-get install gcc
sudo apt-get install g++

这也是需要的:

sudo apt-get install apache2-dev

然后在环境里面,在需求之后,

pip install mod_wsgi
mod_wsgi-express module-config

返回的第二行:

LoadModule wsgi_module "/home/ubuntu/.pyenv/versions/miniconda3-latest/lib/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so"
WSGIPythonHome "/home/ubuntu/.pyenv/versions/miniconda3-latest"

然后在加载模块时,docs 鼓励您粘贴到文件 httpd.conf 中,至少在我的 apache 和 ubuntu 版本中不存在该文件。经过大量阅读,我避免创建一个,也避免将其粘贴到似乎是related 的 apache2.conf 中。相反,按照顶部链接到的 ubuntu 的说明,

编辑此文件:

sudo vi /etc/apache2/mods-available/wsgi.load

将此行粘贴到其中并保存:

LoadModule wsgi_module /path/to/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so

然后运行它并在必要时重新启动 apache 服务器:

sudo a2enmod wsgi

000-default.conf 看起来像这样:

WSGIPythonHome "/home/ubuntu/.pyenv/versions/miniconda3-latest"

<VirtualHost *:80>
    # The ServerName directive sets the request scheme, hostname and port that
    # the server uses to identify itself. This is used when creating
    # redirection URLs. In the context of virtual hosts, the ServerName
    # specifies what hostname must appear in the request's Host: header to
    # match this virtual host. For the default virtual host (this file) this
    # value is not decisive as it is used as a last resort host regardless.
    # However, you must set it for any further virtual host explicitly.
    #ServerName www.example.com

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
        WSGIDaemonProcess helloapp threads=5 python-path=/var/www/html/frontend/  
        WSGIScriptAlias / /var/www/html/frontend/helloapp.wsgi

        <Directory flaskapp>
        WSGIProcessGroup helloapp
        WSGIApplicationGroup %GLOBAL
        Order allow,deny
        Allow from all
        </Directory>

    # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
    # error, crit, alert, emerg.
    # It is also possible to configure the loglevel for particular
    # modules, e.g.
    #LogLevel info ssl:warn

    ErrorLog $APACHE_LOG_DIR/error.log
    CustomLog $APACHE_LOG_DIR/access.log combined

    # For most configuration files from conf-available/, which are
    # enabled or disabled at a global level, it is possible to
    # include a line for only one particular virtual host. For example the
    # following line enables the CGI configuration for this host only
    # after it has been globally disabled with "a2disconf".
    #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

【讨论】:

虽然出于原始问题的目的,这个 000-default.conf 有效,即 Numpy 导入,嗯,这比小说更奇怪,但 scipy 不导入!此外,它甚至不会像import numpy 那样抛出错误消息!要解决此问题,请参阅 here WSGIApplicationGroup %GLOBAL 行需要从它所在的位置移动到 WSGIScriptAlias 行下方 &lt;Directory flaskapp&gt; 应该是 &lt;Directory /var/www/html/frontend&gt;。因为它是你甚至不会使用守护程序模式。由于访问被禁止,Apache 没有使请求失败,这表明您在 Apache 其他地方的权限很松懈,让 Apache 从文件系统的任何位置提供内容。建议你在VirtualHost之外加上WSGIRestrictEmbedded On,如果误用嵌入模式会导致失败。 您的命令(位于底部的 VirtualHost 下方)在自周六以来一直运行良好之后确实破坏了它:Embedded mode of mod_wsgi disabled by runtime configuration: /var/www/html/frontend/flaskapp.wsgi 我现在需要它在线,已经分享了链接,所以希望没有人找到同时破解它的方法,再次删除WSGIRestrictEmbedded On。可能授予对前端文件夹中文件的 execute 权限就足够了,不需要将整个 Python 存储库添加到 www-data 组。将找出安全设置并在一天中的安静时间恢复。 应该会导致任何安全问题,如果 Apache 服务器使用更适合静态文件和 php 应用程序的典型配置,则使用嵌入式模式会有性能和可恢复性问题。阅读blog.dscpl.com.au/2012/10/… 感谢您提供的链接对于具有大内存占用的动态 Web 应用程序来说不一定能很好地工作,当持久保存在内存中时性能会更好。很好,它不会被黑客入侵,它使用大量内存并且到目前为止已经崩溃过一次。将在一周左右尝试将其正确转换为守护程序模式。

以上是关于使用pyenv和virtualenv在apache后面部署flask应用程序时找不到numpy,pandas模块的主要内容,如果未能解决你的问题,请参考以下文章

pyenv、virtualenv、anaconda 有啥区别?

pyenv和virtualenv搭建python虚拟环境

Python 杂记之 如何使用pyenv进行版本管理与如何使用virtualenv创建虚拟运行环境

如何配置全局主管以使用 pyenv 和 virtualenv

python pyenv与 pyenv-virtualenv配置

为啥我不能“停用”pyenv / virtualenv?如何“修复”安装