mod_wsgi とライブラリ読み込み

mod_wsgi とライブラリ読み込み

先日行った、Caffe で推論処理を行う API サーバーの移行時に発生したエラーとその対処法シリーズの第三弾です。

関連エントリーは以下の通りです。

(移行後の)環境

第一弾・第二弾で記載した内容を再掲します。

  • AWS Deep Learning AMI (Ubuntu、移行前は Amazon Linux 版の DL AMI)
  • その他の環境は変わらず
    • caffe_p27 環境
    • Apache 2.4
    • etc.
    • AWS Deep Learning AMI (Ubuntu、移行前は Amazon Linux 版の DL AMI)
  • その他の環境は変わらず
    • caffe_p27 環境
    • Apache 2.4
    • etc.

エラーとその原因

[Sun Jan 27 16:39:56.540744 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856] mod_wsgi (pid=13877): Failed to exec Python script file '/var/www/foo-caffe-api/foo-caffe-api.wsgi'.
[Sun Jan 27 16:39:56.540783 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856] mod_wsgi (pid=13877): Exception occurred processing WSGI script '/var/www/foo-caffe-api/foo-caffe-api.wsgi'.
[Sun Jan 27 16:39:56.540811 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856] Traceback (most recent call last):
[Sun Jan 27 16:39:56.540829 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]   File "/var/www/foo-caffe-api/foo-caffe-api.wsgi", line 10, in <module>
[Sun Jan 27 16:39:56.540887 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]     from api_server import app as application
[Sun Jan 27 16:39:56.540908 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]   File "/var/www/foo-caffe-api/api_server.py", line 42, in <module>
[Sun Jan 27 16:39:56.540966 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]     import caffe
[Sun Jan 27 16:39:56.540976 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]   File "/home/ubuntu/src/caffe_python_2/python/caffe/__init__.py", line 1, in <module>
[Sun Jan 27 16:39:56.541009 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]     from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
[Sun Jan 27 16:39:56.541019 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]   File "/home/ubuntu/src/caffe_python_2/python/caffe/pycaffe.py", line 13, in <module>
[Sun Jan 27 16:39:56.541125 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856]     from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \\
[Sun Jan 27 16:39:56.541144 2019] [wsgi:error] [pid 13877] [remote 127.0.0.1:41856] ImportError: libnccl.so.2: cannot open shared object file: No such file or directory

*.wsgi, *.py を配置して、wsgi の設定をした後、Apache を再起動して API サーバーにアクセスすると、上のようなエラーが出ました。エラーメッセージの末尾に記載されているように、*.so が読み込まれていないのが原因です。ちなみに、同 so ファイルは、findコマンドで存在することは確認済みです。


mod_wsgi とその実行環境の設定

mod_wsgi で動く Python アプリケーションで、(ライブラリ読み込みのための)LD_LIBRARY_PATHや、その他環境変数を設定したいというのは割と良くある話題のようです。mod_wsgi の作者である Graham さんも、以下のような gist を作って、いくつかの方法を紹介しています。

Setting environment variables for Apache/mod_wsgi hosted Python application.

大雑把にまとめると、mod_wsgi で環境を設定する方法は主に

  • *.wsgi ファイルで、os.environ を使って環境変数を設定する
    • その派生形で、*.wsgi から別の *.py ファイルを呼び出し、os.environ で設定する
  • Apache の設定ファイルで、python-pathpython-home を設定する
  • ライブラリ関連は、上の2つの方法ではダメなので、python モジュールインストール時にLD_RUN_PATHを設定する(LD_LIBRARY_PATHは設定不要)

の三通りとなります。

ライブラリ関連の場合、なぜ最初の2つの方法だとダメかという理由ですが、LD_LIBRARY_PATHの読み込み・ライブラリ読み込みは、プロセス起動時に一度だけ行われるからなので、プロセス起動後に設定はできません。

How to set LD_LIBRARY_PATH individually for django web sites with Apache and mod_wsgi – Stack Overflow

では、ライブラリ読み込みの問題は三番目の方法で解決するかというと、そうではありません。この方法は、既にモジュールがインストール済みの場合には使えないので、別の方法を選択する必要があります。

対処法: LD_LIBRARY_PATH を設定

結論としては、第二弾で書いた通りですが、以下に再掲します。

/etc/apache2/envvars で適切な LD_LIBRARY_PATH を設定して、Apache を再起動すれば良いです。

設定すべき LD_LIBRARY_PATH を調べるには、以下のようにします。

ubuntu@ip-nnn-nnn-nnn-nnn:~$ source activate caffe_p27
(caffe_p27) ubuntu@ip-nnn-nnn-nnn-nnn:~$ printenv LD_LIBRARY_PATH
/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/extras/CUPTI/lib64:/lib/nccl/cuda-8.0/lib:/usr/lib64/openmpi/lib/:/usr/local/lib:/usr/lib:/usr/local/mpi/lib:/lib/:/usr/lib64/openmpi/lib/:/usr/local/lib:/usr/lib:/usr/local/mpi/lib:/lib/::/home/ubuntu/anaconda3/envs/caffe_p27/lib/

envvars ファイルには、以下のような行を追加します。

export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:/usr/local/cuda-8.0/extras/CUPTI/lib64:/lib/nccl/cuda-8.0/lib:/usr/lib64/openmpi/lib/:/usr/local/lib:/usr/lib:/usr/local/mpi/lib:/lib/:/usr/lib64/openmpi/lib/:/usr/local/lib:/usr/lib:/usr/local/mpi/lib:/lib/::/home/ubuntu/anaconda3/envs/caffe_p27/lib/

なお、これも前回書いた通りですが、AWS DL AMI のバージョンによって、 LD_LIBRARY_PATH の値は若干異なります。

その他の方法

読み込む so ファイルが1つだけであれば、Apache のLoadFileでも大丈夫そうです。

python – How to set LD_LIBRARY_PATH for apache+wsgi website – Stack Overflow

ただ、今回は、Anaconda 環境の so ファイルを色々と読み込む必要があるので、 LD_LIBRARY_PATHを設定するのが一番簡単な選択肢だと思います。

まとめ

今回で、エラー対処シリーズ三部作は完了です。mod_wsgi は色々と面倒くさかったので(勉強にはなりましたが)、次にサーバーを立てるときには、スタンドアロンサーバーを立てようと思います。

we are hiring

優秀な技術者と一緒に、好きな場所で働きませんか

株式会社もばらぶでは、優秀で意欲に溢れる方を常に求めています。働く場所は自由、働く時間も柔軟に選択可能です。

現在、以下の職種を募集中です。ご興味のある方は、リンク先をご参照下さい。