☆☆ 新着記事 ☆☆

2019年1月11日金曜日

(詳述) Virtualenvとmod_wsgiで、Python Flaskを動かす

以前、virtualenv と venv の違いについて書きましたが、

【 「Pythonの仮想環境  venv と virtualenvのもっとも大きな違い 」 】

その後、調べるにつけ、Pythonアプリはvirtualenv環境下で動かすべき、という記事を沢山見つけましたので、やってみます。


Virtualenv環境

・CentOS 7 に標準のPython 2.7 とは別のバージョン(Python 3.7)をインストール。

・Apache(httpd 2.4)のVirtual Hostは、mod_wsgi開発者のGraham Dumpletonさんが強く推奨する
  Daemon Mode (デーモン・モード)で記述。

・wsgiスクリプトには、virtualenvを自動起動する為の activate_this.py をinvokeする設定を入れます。

途中で解説を入れながら、ステップ・バイ・ステップで、1つずやります。

1. ディレクトリ・ファイル構成
virtualenvでは、仮想環境構築用のディレクトリとPythonアプリ(今回はflask)は、別ディレクトリに作成することが推奨されていますので、それに準拠します。

vitualenv を走らせるには、2つのファイルを記述する事がポイントになります。
・ httpdのconf ファイルに<virtual host>の記述
・ wsgiスクリプト


(仮想環境構築)
 /home/virtual_test
                  |
                  |---virtual_test_child <-- 仮想化する対象のディレクトリーです。
                                  |
                                  |----- bin  <-- activate_this.pyは、ここに自動生成されます。
                                           |-----

(Flaskアプリ)
 /var/www/html/virtual_test_app
                              |-----app.wsgi
                              |-----app.py
                              |----- templates
                                            |---sample01.html
                                            |---sample02.html

では、やってみます。

1. 仮想環境の構築

[@ home]# mkdir virtual_test
[@ home]# cd virtual_test
[@ virtual_test]# mkdir virtual_test_child
[@ virtual_test]# virtualenv virtual_test_child
Using base prefix '/usr/local'
New python executable in /home/virtual_test/virtual_test_child/bin/python3
Also creating executable in /home/virtual_test/virtual_test_child/bin/python
Installing setuptools, pip, wheel...
done.
(virtual_test_child) [@ virtual_test]# python -V
Python 3.6.8
(virtual_test_child) [@ virtual_test]# which python
/home/virtual_test/virtual_test_child/bin/python <-- されます。
(virtual_test_child) [@ virtual_test]# pip freeze
(virtual_test_child) [@ virtual_test]#

2. Pythonのインストール

1)ツールのインストール
(virtual_test_child) [@ virtual_test]# yum groupinstall "development tools"
(エラー表示)
Maybe run: yum groups mark install (see man yum)
No packages in any requested group available to install or update

(対処):epel が上手く機能していない可能性があるため
(virtual_test_child) [@ virtual_test]# yum clean all
(virtual_test_child) [@ virtual_test]# yum --disablerepo=\* --enablerepo=base,updates groupinstall "Development Tools"

(同じエラー表示)
Maybe run: yum groups mark install (see man yum)
No packages in any requested group available to install or update

(確認)
(virtual_test_child) [@ virtual_test]# yum grouplist
Installed Groups:
   Development Tools

うーむ。 グローバルなものが参照されちゃうんですね。

(以上、エラー対処は、2015/12/11
 https://www.centos.org/forums/viewtopic.php?t=55400 を参照しました。)


#yum list installed で確認すると、必要なツールは全て、インストールされている表示になって
しまいます。

なので、これ以上、virtualenv環境でのツールのインストールはしません。

初めて、Pythonをソース・コードからインストールされる方は、こちらも参考にしてみてください。
必要なパッケージをインストールしています。

【 「これで動く (1) !! WebArena VPS(CentOS7)でFlaskを動かす 」 】



virtual_test_child) [@ virtual_test]# wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz
2019-01-09 20:48:59 (10.8 MB/s) - ‘Python-3.7.2.tgz’ saved
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# tar zxvf Python-3.7.2.tgz
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  Python-3.7.2  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# cd Python-3.7.2
(virtual_test_child) [@ Python-3.7.2]# ./configure --enable-shared
(virtual_test_child) [@ Python-3.7.2]#  ./configure --enable-optimizations
(virtual_test_child) [@ Python-3.7.2]# make && make altinstall
(error)
ModuleNotFoundError: No module named '_ctypes'
凄く時間がかかって、この結果はがっかりします。
原因は、 libffi-develがインストールされていないから。
https://bugs.python.org/issue31652

(virtual_test_child) [@ Python-3.7.2]# yum install libffi-devel
の前に、
以下のdependenciesがインストールされているか確認。
(virtual_test_child) [@ Python-3.7.2]# yum list installed | grep -ie httpd-devel -e python-deve
l
httpd-devel.x86_64                     2.4.6-88.el7.centos        @base
python-devel.x86_64                    2.7.5-76.el7               @base

インストールされていますね。

では、
(virtual_test_child) [@ Python-3.7.2]# yum install libffi-devel
Complete!

もう一回、最適化とコンパイル。

(virtual_test_child) [@ Python-3.7.2]#  ./configure --enable-optimizations
(virtual_test_child) [@ Python-3.7.2]# make && make altinstall
Installing collected packages: setuptools, pip
Successfully installed pip-18.1 setuptools-40.6.2

無事にpythonがインストールされました。

3.  mod_wsgiをインストールする

(virtual_test_child) [@ Python-3.7.2]# cd ..  <- pythonをインストールしたdirectoryに戻る
(virtual_test_child) [@ virtual_test]#wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.6.tar.gz
2019-01-10 01:34:34 (932 KB/s) - ‘4.5.6.tar.gz’ saved
(virtual_test_child) [@ virtual_test]# ls -a
.  ..  4.5.6.tar.gz  Python-3.7.2  Python-3.7.2.tgz  virtual_test_child
(virtual_test_child) [@ virtual_test]# tar zxvf 4.5.6.tar.gz

(virtual_test_child) [@ virtual_test]# which python3
/home/virtual_test/virtual_test_child/bin/python3
(virtual_test_child) [@ virtual_test]# deactivate
[@ virtual_test]# cd /
[@ /]# find -name apxs
./usr/bin/apxs
[@ /]# cd /home
[@ home]# ls -a
.  ..  virtual_test
[@ home]# cd virtual_test
[@ virtual_test]# ls -a
.   4.5.6.tar.gz    Python-3.7.2      virtual_test_child
..  mod_wsgi-4.5.6  Python-3.7.2.tgz
[@ virtual_test]# source virtual_test_child/bin/activate
(virtual_test_child) [@ virtual_test]# cd mod_wsgi-4.5.6
(virtual_test_child) [@ mod_wsgi-4.5.6]# ./configure --with-apxs=/usr/bin/apxs --with-python=/usr/bin/python3
configure: creating ./config.status
config.status: creating Makefile

(virtual_test_child) [@ mod_wsgi-4.5.6]# make && make install
Libraries have been installed in:
   /usr/lib64/httpd/modules
chmod 755 /usr/lib64/httpd/modules/mod_wsgi.so <-後でmod_wsgi.soが、pythonのshared libraryを使えているか確認します。

4. Flaskをインストールする

(virtual_test_child) [@ mod_wsgi-4.5.6]# python3 -m pip install flask==
Collecting flask==
(virtual_test_child) [@ mod_wsgi-4.5.6]# pip install flask==1.0.2
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0


必要な環境構築が終わりましたので、各ファイルを置いていきます。

ファイル名:venv_mossymob.tk.conf
設置場所:/etc/httpd/conf.d


LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so

 <VirtualHost *:80>
    ServerName mossymob.tk
 
  WSGIDaemonProcess virtual_test_app user=apache group=apache python-home=/home/virtual_test/virtual_test_child

  WSGIScriptAlias /virtual_test_app /var/www/html/virtual_test_app/app.wsgi

<Directory /var/www/html/virtual_test_app>
 WSGIProcessGroup virtual_test_app
 WSGIApplicationGroup %{GLOBAL}
 Order allow,deny
 Allow from all
</Directory>
    CustomLog /home/virtual_test/access.log common
    ErrorLog /home/virtual_test/error.log
    LogLevel info
  </VirtualHost>


WSGIDaemonProcessへの python-home オプションの指定
(公式: https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html


Embeded ModeやDaemon Modeで1つのアプリケーションを1つのデーモン・グループで使用する場合など、多くの場合、以下のpython-home オプションを、WSGIDaemonProcessに、使用するpythonのルート・ディレクトリを明記してあげれば、この1行だけの追加でVirtualenv に対応できるようになるそうです。

WSGIDaemonProcess myapp python-home=/usr/local/venvs/myapps

Virtualenvで使用するpythonのパスは、
which python や python -c 'import sys; print(sys.prefix)' で、確認できます。

今回は、virtualenv のディレクトリにPythonをインストールしていますので、

(virtual_test_child) [virtual_test]# which python
/home/virtual_test/virtual_test_child/bin/python

(virtual_test_child) [ virtual_test]# python -c 'import sys; print(sys.prefix)'
/home/virtual_test/virtual_test_child

なので、 python-home=/home/virtual_test/virtual_test_child をWSGIDaemon Process で
指定しています。



ファイル名:app.wsgi
設置場所:/var/www/html/virtual_test_app

# coding: utf-8
activate_this ='/home/virtual_test/virtual_test_child/bin/activate_this.py'
with open(activate_this) as file_:
    exec(file_.read(), dict(__file__=activate_this))
import sys
sys.path.insert(0, '/var/www/html/virtual_test_app')
from app import app as application
*activate_this.pyは、virtualenvを作成した際に、binディレクトリ内に自動で生成されています。



ファイル名:app.py
設置場所:/var/www/html/virtual_test_app
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
    message="Hi, there!"
    return render_template("sample01.html", message=message)
   
@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_num']
       
    return render_template("sample02.html", result=result)
if __name__ == '__main__':
    app.run()

ファイル名: sample01.html
設置場所:/var/www/html/virtual_test_app/templates
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/virtual_test_app/add" method="post"> 
<p>Input the number you like:</p>
<input type="text" name="new_num" >
<input type="submit" value="Do">
</form>
 </body>
</html>
*form actionの参照ディレクトリの記述は気をつけましょう。
*sample02.htmlは、resultを表示しているだけですし、今まで多く書いてきていますので
 今回は記述を省略します。


これで、http:mossymob.tk/virtual_test_app にブラウザでアクセスすると、


 
 
無事に値がsample01.htmlからsample02に引き渡されて、
ルーティングもできることが確認できました。


* mod_wsgi が、シェアード・ライブラリを使用できているかの確認。

(シェアド・ライブラリを使えていなくてもmod_wsgiは動きますが、メモリーを大量に消費してい
 思わぬ問題を引き起こす可能性があるそうです。)
 

上でmod_wsgi.soが格納されたdirectoryがありましたが、そこで、以下の ’ldd’ コマンドを実行。

# cd  /usr/lib64/httpd/modules/

[ modules]# ldd mod_wsgi.so
        linux-vdso.so.1 =>  (0x00007ffe424ed000)
        libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007f6138849000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f613862d000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f6138428000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007f6138225000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f6137f23000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f6137b55000)
        /lib64/ld-linux-x86-64.so.2 (0x000055a55f838000)

 以上のようなリストが表示されていれば大丈夫。


これで、お終いです。

参考)
mod_wsgiのモード別の<Virtual Host>の記述方法(公式)
https://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html


(後日再挑戦)

◇virtual host

LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so
  <VirtualHost *:80>
   ServerName uslife.mossymob.tk
   DocumentRoot /var/uslife/html
  <Directory /var/uslife/html>
   Require all granted
  </Directory>
  
   WSGIDaemonProcess forum user=apache group=apache python-home=/home/venv_env/python37
   WSGIScriptAlias /app/forum /var/uslife/html/app/forum/app.wsgi
  
  <Directory /var/uslife/html/app/forum>
  WSGIProcessGroup forum
  WSGIApplicationGroup %{GLOBAL}
    Require all granted
  </Directory>
     CustomLog /home/venv_env/access.log common
     ErrorLog /home/venv_env/error.log
     LogLevel info
  </VirtualHost>

◇ app.py

from flask import Flask,render_template,request
app = Flask(__name__)
@app.route('/')
def index():
    message="Hi, there!"
    return render_template("sample01.html", message=message)
   
@app.route('/add',methods=['POST'])
def add():
    if request.method =='POST':
        result = request.form['new_num']
    #else:
    #    result = "No wish! Ah?"
       
    return render_template("sample02.html", result=result)
if __name__ == '__main__':
    app.run()

◇html
<html>
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 {{message}}
<form action="/add" method="post"> 
<p>Input the number you like:</p>
<input type="text" name="new_num" >
<input type="submit" value="Do">
</form>
 </body>
</html>

これで動く。 まだ、ルーティングの記述方法が良く理解できていないようだ。


sample01.html
http://uslife.mossymob.tk/app/forum/

sample02.html
http://uslife.mossymob.tk/app/forum/add

0 件のコメント:

コメントを投稿