Aimless Blog

Nginx+uWSGIでFlaskを使用する

Tag:
flasknginx

CentOS7でNginx+uWSGI+Flaskを使用したwebアプリのセットアップをしてみます。

pythonインストール

sudo yum install -y python36 python36-libs python36-devel python36-pip

FlaskとuWSGIをインストール

仮想環境下でflaskとuwsgiをpipでインストール。

python3.6 -m venv flask_app
cd flask_app
. bin/activate
pip3 install flask uwsgi

Hello Worldを表示するまで

ファイルの構成はこんな感じになります

flask_app
    ❘-test.py
    ❘-uwsgi.ini
    ❘-venv

test.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
	return "Hello World"

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

nginxの設定

/etc/nginx/conf.d/flask.conf

server {
    listen 80;
    server_name example.com or IP;
    
    location / {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
}

UNIXドメインソケット/tmp/uwsgi.sockを介してnginxとuwsgiを接続します。

uWSGIの設定

以下のコマンドでuwsgiを起動

uwsgi --socket /tmp/uwsgi.sock --module test --callable app --chmod-socket=666

nginxとuwsgiのUNIXドメインソケットのpathは揃えておく。 これでexample.com(またはIPアドレス)にアクセスするとHello Worldが表示されます。
でも毎回上のコマンドを打つのは面倒なので、uwsgi.iniを作ります。

#uwsgi.ini
[uwsgi]

uid = nginx #ユーザー名
gid = nginx #グループ名

module = test  #WSGIモジュールをロードする ここではtest.py
socket = /tmp/%n.sock #デフォルトのプロトコルを使用して、指定されたUNIX / TCPソケットにバインドします
chmod-socket = 666 #パーミッション
callable = app #デフォルトのWSGI呼び出し可能名を設定する

%nはuwsgiのマジック変数でファイル名の拡張子を除いた名前(uwsgi)に置き換えられます。
callableはflaskのapp = Flask(__name__)のappです。
uwsgi.iniを作成したら次のコマンドで起動します。

uwsgi --ini uwsgi.ini

停止はctrl+c。

デーモン化

デーモン化したuwsgiの起動、停止、リロードをするにはpidファイルが必要なので、uwsgi.iniに以下を追加

daemonize = /var/log/uwsgi/%n.log
pidfile = /tmp/flask_app.pid
vacuum = true

daemonize = /var/log/uwsgi/%n.logでデーモン化したときのログファイル置き場を指定。
vacuum = true は起動した時、異常終了した時に残っているpidファイルやsocketをクリアする。

/var/log/にuwsgiディレクトリを作成

sudo mkdir /var/log/uwsgi
sudo chown -R xxx:xxx uwsgi

起動、停止、リロード

uwsgi --ini uwsgi.ini  # 起動
uwsgi --stop /tmp/flask_app.pid  # 停止
uwsgi --reload /tmp/flask_app.pid  # リロード

The uWSGI Emperor

Emperorモードを使うと一つのサーバーで複数のアプリを利用する時に一括で管理できて便利。
The uWSGI Emperor – multi-app deployment

使い方は、/etc/uwsgi/vassalsディレクトリを作成してconfiguration file(uwsgi.ini)のシンボリックリンクを作成します。
複数のアプリがある場合はそれぞれの.iniファイルのシンボリックリンクを作成。

sudo mkdir /etc/uwsgi/vassals
sudo ln -s /var/www/html/flask_app/uwsgi.ini /etc/uwsgi/vassals

uwsgi.iniに以下を追加

chdir = /var/www/html/flask_app  #appをロードする前に指定したディレクトリに移動

このオプションがないと多分起動しない。

手動で起動する場合は以下のコマンドを打って起動

uwsgi --emperor /etc/uwsgi/vassals --logto /var/log/uwsgi/emperor.log

常に起動しておくためにサービスに登録します。
/etc/systemd/system/にuwsgi.serviceを作成。

sudo mkdir /etc/systemd/system/uwsgi.service
#uwsgi.service

[Unit]
Description=uWSGI
After=syslog.target

[Service]
ExecStart=/var/www/html/flask_app/bin/uwsgi --emperor /etc/uwsgi/vassals --logto /var/log/uwsgi/emperor.log
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]
WantedBy=multi-user.target

ExecStart=以下のパスはそれぞれの環境で違う場合があると思うので任意に変更してください。

起動、自動起動、リスタート、停止

sudo systemctl start uwsgi
sudo systemctl enable uwsgi
sudo systemctl restart uwsgi
sudo systemctl stop uwsgi

uwsgi.serviceに間違いがないのにサービスがスタートできない場合は
systemdにユニットファイルを追加・更新したことを通知するコマンド

sudo systemctl daemon-reload

を打つとサービスが起動するかも。

.iniファイルの例

[uwsgi]

uid = nginx
gid = nginx

chdir = /var/www/html/flask_app
module = run
socket = /tmp/%n.sock
chmod-socket = 666
callable = app


master = true
vacuum = true
processes = 2
threads = 1
pidfile = /tmp/flask_app.pid
thunder-lock = true  #falseになっていると複数のuWSGIのプロセスで捌くリクエストに偏りが出てしまう。

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

#daemon
#daemonize = /var/log/uwsgi/%n.log
log-reopen = true
log-maxsize = 8000000

エンペラーモードを使用。
各オプションの詳細は公式サイトを参照してください。