やりたいこと
- Flask + uwsgi + Nginxの構成でAPIを動作させる
環境・MWのバージョン
- Ubuntu20.04
- Python 3.8.10
- Flask 1.0.2
- Nginx 1.18.0
- uwsgi 2.0.20
今回使用する技術の概要
Flaskとは
Pythonの軽量フレームワークです。機能が少ない分リリース用のアーティファクトが軽量になる、習得が簡単であるなどのメリットがあります。
Djangoが中規模以上の開発に適しているのに対してFlaskは小規模な開発に向いています。(機能が限られたAPIをサブシステムとして構築する際に選択肢になるでしょう。)
uwsgiとは
Pythonのアプリケーションを動作させるためのアプリケーションサーバ用MWです。
機能が豊富で動作が速いことがメリットとして挙げられます。
uwsgiを使うにあたってはWSGIを理解しておく必要があります。
WSGIとは(Web Server GateWay Interface)の略で、Webサーバとアプリケーションサーバを繋ぐインタフェースの規格です。
uwsgiはこのWSGIに準拠したミドルウェアです。
Nginxとは
オープンソースのWebサーバ用MWです。
Apacheと比較して静的リソースの大量処理が得意な事やメモリ消費量が小さいことが特徴です。
(逆にApacheよりも動的リソースの処理が苦手です。)
作業手順
それぞれのMWが単体で動作することを確認した後、疎通確認をします。
-
Flaskの動作確認
- インストールする
- ビルトインサーバで動作確認する
-
Nginxの動作確認
- インストールする
- 静的ページを表示する
-
uwsgiの動作確認
- インストールする
- 動作確認する
-
Flask ⇔ uwsgi ⇔ Nginxの疎通確認
- Nginxの設定
- uwsgiの設定
- 疎通確認
Flaskの動作確認
インストールする
※ Python3系がインストールされていることは前提とします。
以下のコマンドでFlaskをインストールします。
(Jinja2, itsdangerous, requests, WerkzeugはFlaskを動作させるために必要なパッケージです。)
$ pip install Flask==1.0.2 Jinja2==3.0.1 itsdangerous==2.0.1 requests==2.21.0 Werkzeug==2.0.1
正しくインストールされていることが確認できればOKです。
$ pip show flask
Name: Flask
Version: 1.0.2
Summary: A simple framework for building complex web applications.
Home-page: https://www.palletsprojects.com/p/flask/
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
License: BSD
Location: /usr/local/lib/python3.8/dist-packages
Requires: Werkzeug, click, Jinja2, itsdangerous
Required-by: Flask-Testing, Flask-SQLAlchemy, Flask-RESTful, Flask-Migrate, flask-marshmallow, Flask-Mail, Flask-Login, Flask-JWT, Flask-JWT-Extended, Flask-Cors, Flask-Bcrypt, Bcrypt-Flask
ビルトインサーバで動作確認をする
サンプルプログラムのディレクトリ構成は以下の通りです。
/tmp/flask_sample/ # プロジェクトのルートディレクトリ
├── app
│ └── __init__.py # アプリケーション本体とエンドポイントを記述する
└── manage.py # アプリケーションを読み込んで起動する
# Flaskで利用するパッケージをインポートする
from flask import Flask, jsonify
# アプリケーションオブジェクトを生成する
application = Flask(__name__)
# エンドポイントを作る(http://host/hello にリクエストするとJSONが表示される)
@application .route("/hello")
def hello():
return jsonify({
"message": "Hello World!"
})
# appディレクトリからアプリケーションオブジェクトをインポートする。
from app import application
# Pythonスクリプトとして実行された場合、アプリケーションを実行する。
if __name__ == "__main__":
application.run()
ここで、Flask単体の動作確認をします。
# プロジェクトのルートディレクトリに移動する
$ cd /tmp/flask_sample
# ビルトインサーバを起動する
$ flask run
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
※ ビルトインサーバ起動時に警告が表示されますが一旦無視してOKです。
ブラウザから http://localhost:5000/hello
にアクセスして以下のように表示されれば確認完了です。
Nginxの動作確認
インストールする
以下のコマンドでインストールします。
$ sudo apt-get update
$ sudo apt-get -y install nginx
静的ページを表示する
インストール後、Nginxを起動してブラウザで動作確認します。
$ service nginx start
デフォルトページが表示されれば完了です。
uwsgiの動作確認
インストールする
$ apt-get update
# 各種依存パッケージをインストールする
$ apt-get install -y build-essential python-dev pip
# pipでuwsgiをインストールする
$ pip install uwsgi
動作確認する
$ cd /tmp/flask_sample
$ uwsgi --http=0.0.0.0:8000 --wsgi-file=/tmp/flask_sample/manage.py --callable=application
--wsgi-fileオプションでwsgiから動作させるファイルを指定し、--callableオプションでアプリケーションオブジェクトを指定します。
このとき必ずプロジェクトのルートディレクトリ(今回の場合は/tmp/flask_sample)に移動します。
理由は、manage.pyが相対インポートでapplicationオブジェクトを参照できるようにするためです。
ブラウザから http://localhost:8000/hello
にアクセスして画像のように表示されれば成功です。
ここまで完了したら一旦各MWの動作確認は完了です。
Flask ⇔ uwsgi ⇔ Nginxの疎通確認
ここからはいよいよNginx・uwsgi・Flaskを組み合わせて動かします。
Nginxの設定
まずはクライアントのリクエストを受け付けるWebサーバとしてNginxの設定を変更します。
/etc/nginx/conf.d下にuwsgi.confを作成し、以下の内容を記述します。
server {
# 80番ポートを開放する
listen 80;
# "/"から始まるURIに{}内の設定を適用する
location / {
# uwsgiのパラメータを読み込む
include uwsgi_params;
# uwsgiとの通信に用いるソケットファイルを指定する(パスは任意)
uwsgi_pass unix:///tmp/uwsgi.sock;
}
}
続いて、uwsgi.confの設定がNginxに読み込まれるよう ```/etc/nginx/nginx.confの設定を変更します。
# ファイルの真ん中あたりにあります
# /etc/nginx/conf.d下の拡張子.confのファイルを全て読み込む
# ※ 前項のuwsgi.confもここで読み込まれます
include /etc/nginx/conf.d/*.conf;
# この記述をコメントアウトする
#include /etc/nginx/sites-enabled/*;
uwsgiの設定
続いてuwsgiの設定をします。
先ほどはuwsgiコマンドにオプションを指定して実行していました。しかし、設定項目が多くなると
毎回オプションを指定するのが面倒ですし、設定ミスも増えます。
そこで、設定ファイルでオプションを指定する方法を取りましょう。
/tmp/flask_sample下にwsgi.iniを作成します。
ディレクトリ構成は以下のようになります。
/tmp/flask_sample/
├── app
│ └── __init__.py
├── manage.py
└── wsgi.ini # 新規追加ファイル
/tmp/flask_sample/wsgi.iniを次のように編集します。
[wsgi]
# wsgiの実行時にプロジェクトのルートディレクトリに移動する
chdir = /tmp/flask_sample
# wsgiで動作させるファイルのパス
wsgi-file = /tmp/flask_sample/manage.py
# アプリケーションオブジェクトの変数名
callable = application
# ソケットファイル
socket = /tmp/uwsgi.sock
# ソケットファイルの権限
chmod-socket = 666
# root権限で実行する
master = true
chdirでプロジェクトのルートディレクトリに移動しないと相対インポートが正しく動かない可能性があるので忘れずに設定します。(インターネット上の記事では全てのファイルを1つのディレクトリに配置しているため、chdirが省略されていることが多いです。しかし、実際のプロジェクトではそのようなケースは稀なのでchdirを指定するのが無難でしょう。)
疎通確認
ここまでの設定で、サーバのルートディレクトリにリクエストが来ると/tmp/uwsgi.sockに繋げる⇒
uwsgi.sockからmanage.pyが呼び出されてFlaskアプリケーションが実行される という処理が行われるようになりました。
以下のコマンドでwsgiを起動しましょう。
$ uwsgi --ini /tmp/flask_sample/wsgi.ini
ブラウザから http://localhost:8000/hello
にアクセスしてレスポンスが表示されれば動作確認完了です。