Python
Flask
uwsgi
Python3
LNUP

Amazon Linux に python3 + Flask + uWSGI + nginx を導入し、本番運用に耐えるウェブサーバを構築

More than 1 year has passed since last update.

この記事は

「AWS EC2 に Python の演算結果を Json で出力する API サーバを10分で構築」

http://qiita.com/kent_ocean/items/12e44ea4456c1e869bad

の続きです。

前回の記事で Flask を使った APIサーバ を構築したわけですが、Flask の Run メソッドはあくまでも開発用サーバとして使うもので、本番環境には適しません。

今回は、Flask に uWSGI と nginx を組み合わせ、nginx からリバースプロキシして uWSGI で Flask アプリを動かす構成にして、本番での運用に耐えるサーバを作ろうと思います。

あと、どうでもいいことですが、とりあえず僕はこの構成を LNUP と勝手に命名することにしました。(LNUP = Linux + nginx + uWSGI + python)

(他の呼び方がありましたら教えてください)


前提条件

今回の記事は以下の環境で手順を検証しています。

Version

OS
Amazon Linux AMI 2016.03.3 (ami-374db956)

Python
3.5.2

Flask
0.11.1


導入するソフトウェアのバージョン

今回の記事で実際にインストールしたソフトウェアのバージョンは以下の通り

Version

uWSGI
2.0.13.1

nginx
1.11.1


uWSGIのインストールと設定


インストール

pip install uwsgi


設定ファイルの作成

flask の py ファイルと同じ階層に設定ファイルを作成します。

cd /var/www/flask

sudo vim uwsgi.ini


uwsgi.ini

[uwsgi]

#application's base folder
base = /var/www/flask

#python module to import
app = hello_world
module = %(app)

#socket file's location
socket = /var/www/flask/tmp/uwsgi.sock
#socket = /tmp/uwsgi.sock

#permissions for the socket file
chmod-socket = 666

#the variable that holds a flask application inside the module imported at line #6
callable = app

#location of log files
logto = /var/log/uwsgi/%n.log

master = true
processes = 1
vacuum = true
die-on-term = true



log を入れるディレクトリを作成

sudo mkdir -p /var/log/uwsgi

sudo chmod o+w /var/log/uwsgi


テストコードを作成

sudo vim hello_world.py


hello_world.py

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
return "Hello World!"

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


※ Flask 公式にある Hello World をそのまま転載

http://a2c.bitbucket.org/flask/quickstart.html

※ runメソッドに IPアドレスやポート番号、スレッド処理フラグなどの引数を付ける必要はありません。


Nginx1.11をインストール

Amazon Linux 標準のリポジトリからインストールすると Nginx 1.8 になってしまうので、nginx のリポジトリを参照するよう変更します。

sudo rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm

sudo vim /etc/yum.repos.d/nginx.repo


nginx.repo

name=nginx repo

-baseurl=http://nginx.org/packages/centos/6/$basearch/
+baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/
gpgcheck=0
enabled=1
+priority=1


Nginx のバージョンを確認

sudo yum install nginx

nginx -v
nginx version: nginx/1.11.1


sites-available と sites-enabled の作成

site-available ディレクトリに設定ファイルを置いておき、必要な設定だけをシンボリックリンクで sites-enabled に置く構成にします。

sudo mkdir /etc/nginx/sites-available

sudo mkdir /etc/nginx/sites-enabled


Nginx 設定ファイルを作成

sudo vim /etc/nginx/sites-available/uwsgi.conf


uwsgi.conf

server {

listen 80;
error_log /var/log/nginx/error.log warn;

location / {
include uwsgi_params;
#uwsgi_pass unix:///tmp/uwsgi.sock;
uwsgi_pass unix:///var/www/flask/tmp/uwsgi.sock;
}
}


sudo vim /etc/nginx/nginx.conf


nginx の設定ファイルに sites-enabled を含む記述を追加


nginx.conf

#include /etc/nginx/conf.d/*.conf;

+ include /etc/nginx/sites-enabled/*;

※こう書けば nginx は default.conf を読まずに uwsgi.conf の設定だけを読み込むようになります。


シンボリックリンクを作成

cd /etc/nginx/sites-enabled/

sudo ln -s ../sites-available/uwsgi.conf


設定が正しいかどうか確認

sudo service nginx configtest


nginx の設定を再読込

sudo service nginx reload


権限設定

uWSGI の実行ユーザーが /var/www/flask/tmp に socket を作成できるよう権限を設定します。

sudo chmod o+w /var/www/flask/tmp

nginxが /var/www/flask/tmp の socket にアクセスできるよう権限を設定します。

sudo chown nginx:nginx /var/www/flask/tmp


uWSGI を起動

cd /var/www/flask

uwsgi --ini uwsgi.ini


ブラウザからアクセス

http://(IP Address):80

ブラウザに「Hello world!」と表示されれば成功です。


補足

今回の手順では、uWSGI の socket ファイルが /var/www/flask/tmp ディレクトリ下に生成される設定で進めてみました。

ネットでぐぐると /tmp 直下にしている方が多いようなんですが、本当にここで良いのかなという疑問があったので。。。

で、この設定で進めていくと

↓こんなエラーや

connect() to unix:////var/www/flask/tmp/uwsgi.sock failed (2: No such file or directory) while connecting to upstream,

↓こんなエラー

invalid host in upstream "/var/www/flask/tmp/uwsgi.sock"

が出まくって結構苦労しました。

まあ、結局ほとんど権限設定に起因する問題なので


  1. uWSGI の実行ユーザーが、指定ディレクトリに socket ファイルを書き込む権限の有無

  2. nginx が、socket ファイルが生成されているディレクトリにアクセスする権限の有無

の2点に注意して、nginx と uWSGI のエラーログを見ていけば何とかなるんですが。

もうちょっと良い運用方法があるような気がしますが、、、今後の検討課題かなー。

以上です。