CentOS7+nginx+apache2.4+Python3の環境を作る-apacheとの連携からbottleを使う

前回はpipの設定とmod_wsgiのインストールをしました。今回はapacheとmod_wsgiの連携となります。

注意点

この記事の時点ではまだnginxはいないため、apacheは80番ポートで動いてます。今回の記事はmod_wsgiとapacheを連携してbottleまで動かします

環境

  • ベンダー:さくらのクラウド
  • OS:CentOS7
  • フロント:nginx(80番ポート)
  • バックエンド:Apache2.4(8080番ポート)
  • Python:3系(pyenvを使用)
  • フレームワーク:bottle(8081番ポート)

基本的にsudo環境にする予定です。

手順

基本的には以下の手順になります

  1. Apacheのインストール
  2. Python(pyenv)のインストール
  3. pipの設定
  4. Apache+Pythonの連携←ここ
  5. nginxを使ってリバースプロキシ

今回の記事について

今回は手順の4を行います。bottleも使います。nginxとのリバースプロキシが不要の場合は今回の記事で完結となります。

現在の状態

現在はnginxはいないため、このようにそれぞれインストールはされているけど連携はされていないという状態です。今回はこれらを連携させてブラウザで表示できるようにします。

bottleも表示できるようにします

Pythonのフレームワークbottleも使います。なのでnginxとのリバースプロキシが不要な方は今回で終わりです

apacheとmod_wsgiの連携

現在Pythonは使えますが、ブラウザで実際に見るとなるとできません。コマンドでしか実行できません。apacheにはPythonを表示する方法がありません ※例外としてCGIモードにすれば実行できます。 CGIモードだとbottleが使えないかもしれないので、apacheでもPythonを実行できるようにするのがmod_wsgiというモジュールになります。 このモジュールがいることでブラウザでもPythonが使えるようになります 連携させることでこのようになります。mod_wsgiとPythonのとこ連携となっているのは、apacheと連携しても使えないためになります。実際にやっていきたいと思います。

apacheとmod_wsgiを連携させる

まずかmod_wsgiのインストール場所を確認します [c] [macan@localhost ~]$ pip show mod_wsgi Name: mod-wsgi Version: 4.6.5 Summary: Installer for Apache/mod_wsgi. Home-page: http://www.modwsgi.org/ Author: Graham Dumpleton Author-email: Graham.Dumpleton@gmail.com License: Apache License, Version 2.0 Location: /usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages Requires: Required-by: [/c] Locationの位置になります。

mod_wsgiをコピーして移動させる

僕のsudo権限ではlsを許可していないため、rootになります。sudoでもlsを許可している方はsudo権限でも問題ありません。 [c] [root@localhost ~]# ls -all /usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages/mod_wsgi/server/ -rwxr-xr-x 1 root root 945600 11月 12 01:00 mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so [/c] モジュールがいました。拡張子.soとなっています。soファイルって何?って方は.soファイルって何?どんなファイルなんですか!を見てください

/etc/httpd/modules/にコピー

[c] [root@localhost ~]# cp /usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so /etc/httpd/modules/ [/c] モジュールをコピーしました。実際にあるか確認します [c] [root@localhost ~]# ls /etc/httpd/modules/ mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so [/c] ありました。

Apacheの設定を変更

今やったのはモジュールのコピーです。実際にApacheで動くか確認するため、confファイルなどをいじります。尚、今回のドキュメントルートはApacheのデフォルトの/var/www/html/となります。

httpd.confを修正

httpd.confの最後尾に追記します [c] LoadModule wsgi_module modules/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so WSGIScriptAlias / /var/www/html/adapter.wsgi [/c] 追記をしたら保存をし、シンタックスエラーがないか確認します [c] [root@localhost ~]# httpd -t AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using localhost.localdomain. Set the 'ServerName' directive globally to suppress this message Syntax OK [/c] Syntax OKがあるので再起動します。AH00558というのは無視して問題ありません。ServerNameがないよって奴なのでドメインなど設定すると消えます。

Apacheの再起動

[c] [root@localhost ~]# service httpd restart Redirecting to /bin/systemctl restart httpd.service [/c] 再起動をします 追記したのは二つあります

adapter.wsgiの作成

adapter.wsgiを作成していきます。wsgiを動かすのに必要なファイルだと思ってください。 [c] [root@localhost ~]# vi /var/www/html/adapter.wsgi def application(environ,start_response): status = '200 OK' output = b'Hello World!' response_header = [('Content-type','text/plain'), ('Content-Length',str(len(output)))] start_response(status,response_header) return [output] [/c] 保存をしたら、http://ipアドレス/にアクセスしてみてください このようにでたら連携は成功です。 このままPython(bottle)を使ってみたいと思います

Python(bottle)との連携

Apacheとmod_wsgiの連携はできました。このままではPythonを使った事にはなりませんので今度はbottleとの連携をします

bottleのインストール

まずはbottleをインストールします。bottle自体1つのPythonファイルのためインストールは二つあります

  • pipを使ってインストール
  • wget、SFTPでアップロード

一つ前の記事では、基本的にPython関係は全てpipでインストールすると伝えました。bottleのような単一ファイルならwgetとかでも問題ないです。記事の最後にこのあたりは書いておきます。今回はwgetで持ってきます [c] [root@localhost ~]# cd /var/www/html/ [root@localhost html]# pwd /var/www/html [root@localhost html]# wget https://raw.githubusercontent.com/bottlepy/bottle/master/bottle.py --2018-11-12 18:58:42-- https://raw.githubusercontent.com/bottlepy/bottle/master/bottle.py raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 151.101.228.133 raw.githubusercontent.com (raw.githubusercontent.com)|151.101.228.133|:443 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 200 OK 長さ: 170188 (166K) [text/plain] bottle.py' に保存中 100%[==================================================================================================================================================================================================================================================================================>] 170,188 --.-K/s 時間 0.05s 2018-11-12 18:58:43 (3.19 MB/s) - bottle.py' へ保存完了 [170188/170188] [/c] -bash: wget: コマンドが見つかりませんと言われたら、 [c] [root@localhost html]# yum install wget 読み込んだプラグイン:fastestmirror Loading mirror speeds from cached hostfile epel/x86_64/metalink | 7.7 kB 00:00:00 * elrepo: ftp.ne.jp * epel: mirrors.aliyun.com base | 3.6 kB 00:00:00 elrepo | 2.9 kB 00:00:00 epel | 3.2 kB 00:00:00 extras | 3.4 kB 00:00:00 updates | 3.4 kB 00:00:00 (1/2): epel/x86_64/updateinfo | 931 kB 00:00:00 (2/2): epel/x86_64/primary | 3.6 MB 00:00:00 epel 12703/12703 依存性の解決をしています --> トランザクションの確認を実行しています。 ---> パッケージ wget.x86_64 0:1.14-15.el7_4.1 を インストール --> 依存性解決を終了しました。 依存性を解決しました

Package アーキテクチャー バージョン リポジトリー 容量

インストール中: wget x86_64 1.14-15.el7_4.1 base 547 k トランザクションの要約

インストール 1 パッケージ 総ダウンロード容量: 547 k インストール容量: 2.0 M Is this ok [y/d/N]: y Downloading packages: wget-1.14-15.el7_4.1.x86_64.rpm | 547 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction インストール中 : wget-1.14-15.el7_4.1.x86_64 1/1 検証中 : wget-1.14-15.el7_4.1.x86_64 1/1 インストール: wget.x86_64 0:1.14-15.el7_4.1 完了しました! [/c] これでOKです。再度wgetしてみてください

adapter.wsgiを書き換える

先ほど作成したwsgiファイルを書き換えます [c]

-*- coding:utf-8 -*-

import sys, os dirpath = os.path.dirname(os.path.abspath(__file__)) sys.path.append(dirpath) os.chdir(dirpath) import bottle import index application = bottle.default_app() [/c]

index.pyファイルを作成

続いてindex.pyファイルを作成します [c]

coding: utf-8

from bottle import route, run, template from bottle import TEMPLATE_PATH @route('/') def index(): return ("Apacheとbottleの連携成功!") if __name__ == '__main__': run(host='0.0.0.0', port=8081, debug=True, reloader=True) [/c] 書いたらApacheの再起動をします [c] [root@localhost html]# service httpd restart Redirecting to /bin/systemctl restart httpd.service [/c] 再起動したらhttp://IPアドレス/にアクセスします。日本語で表示されていたらbottleとの連携成功です bottleとの連携は成功したので、今度はテンプレートを使ってみます

jinja2を使用

Pythonではテンプレートとしてjinja2が使われるため、これをインストールします [c] [root@localhost html]# pip install jinja2 Collecting jinja2 Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB) 100% |████████████████████████████████| 133kB 2.9MB/s Collecting MarkupSafe>=0.23 (from jinja2) Downloading https://files.pythonhosted.org/packages/08/04/f2191b50fb7f0712f03f064b71d8b4605190f2178ba02e975a87f7b89a0d/MarkupSafe-1.1.0-cp36-cp36m-manylinux1\_x86\_64.whl Installing collected packages: MarkupSafe, jinja2 Successfully installed MarkupSafe-1.1.0 jinja2-2.10 [/c] pipでインストールしました。インストール場所を調べます [c] [root@localhost html]# pip show jinja2 Name: Jinja2 Version: 2.10 Summary: A small but fast and easy to use stand-alone template engine written in pure python. Home-page: http://jinja.pocoo.org/ Author: Armin Ronacher Author-email: armin.ronacher@active-4.com License: BSD Location: /usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages Requires: MarkupSafe Required-by: [/c] mod_wsgiと同じところにいました。基本的に同じ階層にいないといけないのでコピーします [c] [root@localhost html]# cp -R /usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages/jinja2/ /var/www/html/ [root@localhost html]# ls -all 合計 192 -rw-r--r-- 1 root root 196 11月 1 20:11 adapter.wsgi -rw-r--r-- 1 root root 170188 11月 1 18:58 bottle.py -rw-r--r-- 1 root root 272 11月 1 20:53 index.py drwxr-xr-x 3 root root 4096 11月 1 20:58 jinja2 [/c] 同じ箇所にもってきました

viewsフォルダを作成

bottleでjinja2を動かす時は、viewsフォルダの中に入れないといけません。ではそこにtop.htmlを作ってみてbottleで読み込んでみたいと思います [c] [root@localhost html]# mkdir views [/c]

top.htmlを作成

[c] [root@localhost html]# cd views/ [root@localhost views]# vi top.html [/c]

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>無題ドキュメント</title>
</head>
<body>
<h1>Apacheとbottleの連携成功!(HTMLで表示している)</h1>
</body>
</html>

HTMLの作成はこれで終わりです。

index.pyの修正

index.pyを今度は修正します [c]

coding: utf-8

from bottle import route, run, template from bottle import TEMPLATE_PATH, jinja2_template as template #jinjaを使うように変えてます @route('/') def index(): return template('top') #topのテンプレートを指定してます if __name__ == '__main__': run(host='0.0.0.0', port=8081, debug=True, reloader=True) [/c] http://IPアドレスにアクセスしてHTMLが表示されていればOKです

終わりに

apacheとPythonの連携はこれで終わりです。nginxを使う予定がない場合はこのままbottleを使っていただければ解決です。次回はフロントにnginxを置いてapacheにリバースプロキシをする方法を紹介します

なぜmod_wsgiをモジュールに持ってきたのか

僕が何度かpyenvとmod_wsgiの連携をしましたが、ことごとく失敗しました。色々調べて行けばいくほど泥沼にはまるようになりました。 yumだと上手くいくけど2.7、pipだと3だけど連携できない。モジュールのロードなのかpythonの読み込みなのかよくわからないという事が続きました。

  • apacheのモジュール: /etc/httpd/modules/
  • pipでのインストール箇所:/usr/local/pyenv/versions/3.6.7/lib/python3.6/site-packages

とすぐ理解できる人ならpip指定すれば良いなどになりますが、おそらくここまでやってみた人も多くは途中で挫折したりlogwのコードをコピペしても失敗しているかもしれません。 ※GCPやほかのクラウドではうまくいかない等考えられるため 混乱でさらにモジュールがどこ?となるよりは、apace関連のモジュールなので同じとこにいれてしまえば、後はそこから読み込めば良いとなります。そのためモジュールをコピーして移動させてます

なぜbottleをpipではなくwgetにしたのか?

bottleも同じで、連携するときに結構四苦八苦しました。pipでインストールしたらどこにでるのか、どこにおけばいいのかなど色々悩みましたが、とあるサイトでbottleは1ファイルだけしかないのでpipとか使うよりwgetで落としてきた方が良いと見ました 実際にwgetで落としてきたら楽だったのでこの方法を採用しました