Gunicorn + Flask + nginx で Python の Web アプリ入門

完成図

この記事では、以下の順でアプリケーションを作成します。

  1. Python アプリケーションで Hello World を実行
  2. 動的 Web サーバー(アプリケーションサーバー)で Hello World を実行
  3. Web アプリケーションフレームワークで Hello World を実行
  4. 静的 Web サーバーで Hello World を実行

静的Webサーバ
- コンピューター (ハードウェア) と HTTP サーバ (ソフトウェア) から構成されます。
- サーバが保持しているファイルをブラウザーへ「そのまま」送る

動的Webサーバ
- 静的Webサーバと一般的にはアプリケーションサーバとデータベースからなります
- 保持しているファイルを変更してから、HTTP サーバを通してブラウザーに送る

https://developer.mozilla.org/ja/docs/Learn/Common_questions/What_is_a_web_server より
関連記事:サーバー
スポンサーリンク

Python アプリケーションで Hello World

まずは「Hello World」と表示する単純なアプリケーションを作成します。

Python アプリケーションで Hello World を実行
echo 'print("Hello World")' > local.py
python3 local.py
Hello World
スポンサーリンク

アプリケーションサーバーで Hello World

アプリケーションサーバーとは、動的 Web サーバー (HTTP リクエストを利用して外部のコンピュータからプログラムの実行を受け付けるサーバー) です。

アプリケーションサーバーを利用して、外部のコンピュータから「Hello World」を実行します。

アプリケーションサーバーで Hello World を実行

Python でよく利用するアプリケーションサーバーは以下の3つです。

  • Gunicorn
  • Nginx Unit
  • uWSGI

今回はアプリケーションサーバーに「Gunicorn」を利用します。

なお、「Gunicorn」と 「Python アプリケーション」を接続するために「WSGI」と呼ばれる仕様を利用します。

WSGI アプリケーションの作成

Python アプリケーション側で満たすべき「WSGI」の仕様は以下の3つです。

  1. 引数「環境変数」と「ステータスコードレスポンスヘッダ」を設定するオブジェクトを持つ関数
  2. 第2引数を使って「ステータスコード」と「レスポンスヘッダ」をセットする
  3. バイト列を戻り値とする

それでは、「Hello World」と表示する WSGI アプリケーションを作成します。

vim wsgi.py
def app(env, start_response): #2つの引数を持つ関数
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, response_headers) #ステータスコードとレスポンスヘッダをセット
    return [b'Hello World\n'] #バイト列を戻り値とする

Gunicorn の使い方

外部のパソコンから HTTP リクエストを利用して WSGI アプリケーションを実行するために、アプリケーションサーバーである「Gunicorn」を用意します。

pip3 install Gunicorn

「gunicorn <モジュール名>:<関数名>」コマンドで WSGI アプリケーションを gunicorn

gunicorn wsgi:app

別端末から HTTP リクエストを利用して WSGI アプリケーションを実行します。

curl localhost:8000
Hello World

HTTP リクエストを利用して「Hello World」アプリケーションが実行できました。

パスで動作を変更

HTTP リクエストの指定するパスによって WSGI アプリケーションの動作を以下のように変更します。

  • パスに「/」を指定すると「Hello World」を表示
  • パスに「/other」を指定すると「Other World」を表示
vim wsgi_path.py
def app(env, start_response): #2つの引数を持つ関数
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, response_headers) #ステータスコードとレスポンスヘッダをセット

    if env.get("PATH_INFO") == "/": # "/" パス
        return [b'Hello World\n'] #バイト列を返す
    if env.get("PATH_INFO") == "/other": # "/other" パス
        return [b'Other World\n'] #バイト列を返す
gunicorn wsgi_path:app

パス「/」と「/other」でアプリケーションを実行します。

curl localhost:8000/
Hello World
curl localhost:8000/other
Other World
スポンサーリンク

Web アプリケーションフレームワークで Hello World

毎回「WSGI の仕様」に準拠したり「パスで動作を変更」機能を実装するのめんどくさいな〜〜〜。

という方のために Web アプリケーションフレームワークと呼ばれる「Web アプリケーション開発でよく利用する機能を集めたもの」があります。

Web アプリケーションフレームワークで Hello World を実行

Python でよく利用する Web アプリケーションは以下の3つです。

  • Flask
  • Django
  • Tornado

Flask で WSGI アプリケーションを作成

今回は Web アプリケーションフレームワークFlask を利用して、「WSGI の仕様」に準拠したアプリケーションを作成します。

Web アプリケーションフレームワークで Hello World を実行
pip3 install flask
vim flask_app.py
from flask import Flask
  
app = Flask(__name__)

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

@app.route('/other')
def other():
    return 'Other World\n'

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

なお、flask アプリケーションのソースコードが長くなってきた場合、以下の方法でソースコードを分割することもできます。

Flask の組み込みサーバーを起動

以下のいずれかの方法で Flask の組み込みサーバーを起動します。(1. 2 どちらでもOK

python3 flask_app.py
export FLASK_APP=flask_app.py
flask run -h 127.0.0.1 -p 5000

これからFlaskアプリケーションを始める場合、app.run()flask runのどちらを使用するべきでしょうか?

残念ながら、明確な答えはありません。

https://www.twilio.com/blog/how-to-run-a-flask-application-jp
curl localhost:5000
Hello World
curl localhost:5000/other
Other World

なお、Flask の組み込みサーバーはテスト用です。

本番環境で利用する場合は、アプリケーションサーバー (Gunicorn 等) と組み合わせてください。

This launches a very simple builtin server, which is good enough for testing but probably not what you want to use in production.

https://flask.palletsprojects.com/en/2.0.x/quickstart/

Gunicorn サーバーで Flask を起動

gunicorn flask_app:app
curl localhost:8000/
Hello World
curl localhost:8000/other
Other World

「パスで動作を変更」で作成した WSGI アプリケーションと同じものを Flask アプリケーションフレームワークで作成できました。

静的 Web サーバーで Hello World

本番稼働したらアクセスが多すぎて動かなくなっちゃった!という時は「動的 Web サーバー」の前段に「静的 Web サーバー」を配置します。

リクエストの度に動的に Web ページを生成するのはサーバーに負荷がかかるので、静的 Web ページの場合は静的 Web サーバーに任せましょう。

完成図

「静的 Web ページ」と「動的 Web ページ」の使い分けの例は以下のとおりです。

  • ホームページを表示する:毎回同じ内容でいいので静的 Web ページ
  • 売上ランキングを表示する:売上ランキングは変化するので動的 Web ページ

nginx の使い方

nginx の詳細については以下の記事をご覧ください。

sudo amazon-linux-extras install nginx1 -y
sudo sh -c 'echo "This page is static" > /usr/share/nginx/html/static.html'

パス「/」・「/other」に対する nginx へのリクエストは、Gunicorn に転送するように設定します

sudo vim /etc/nginx/conf.d/proxy.conf
server {
    listen 80;
    root /usr/share/nginx/html/;

    location /hello {
        proxy_pass  http://localhost:8000/;
        }
        location /other {
                proxy_pass  http://localhost:8000/other;
        }
}
sudo systemctl start nginx.service
gunicorn flask_app:app
curl localhost:80/static.html
This page is static

静的 Web ページにアクセスできたこと確認しました。

curl localhost:80/hello
Hello World
curl localhost:80/other
Other World

ポート 80(nginx)にアクセスして、Gunicorn で稼働しているアプリケーションの内容が返ってきていることを確認しました。

関連記事

関連記事:サーバー