Python
Python3
gunicorn
FastAPI
uvicorn
14
どのような問題がありますか?

投稿日

更新日

Organization

FastAPI、uvicorn + gunicorn で デーモン化したWebサーバーの起動、確認、停止方法

経緯

  • 1つのAWSインスタンスで、複数のgunicornプロセスを起動することを検討している
  • 間違えて、他のプロセスを停止しないように、よい方法を模索している

環境

  • AWS
  • Ubuntu 20.04.2 LTS
  • Python 3.8.10 (venvで環境構築)
uvicorn==0.14.0
gunicorn==20.1.0
setproctitle==1.2.2
fastapi==0.65.2

用語の整理

Uvicornとは

Uvicorn is a lightning-fast ASGI server implementation, using uvloop and httptools.
*2より抜粋

  • ASGI server の実装

ASGI とは

ASGI (Asynchronous Server Gateway Interface) is a spiritual successor to WSGI,
*5より抜粋

  • WSGI の 精神的続編 (*6 より)

WSGI とは

The Web Server Gateway Interface (WSGI, pronounced whiskey[1][2] or WIZ-ghee[3]) is a simple calling convention for web servers
to forward requests to web applications or frameworks written in the Python programming language.
*4より抜粋

  • Pythonで書かれたWebアプリケーションに、フォワードするWebサーバーのインターフェース定義
  • ウィスキーと発音することがあるみたいだ (英語の解説動画を見てるとウィスキーと聞こえる)

Uvicornとは (2回目)

  • Pythonで書かれたWebアプリケーションに、フォワードするWebサーバーのためのインターフェース定義の
  • 精神的続編である ASGIを実装したサーバー
  • 正確な表現ではないが、PythonでWebアプリを作って、Webサーバー化してくれる、と考えればよいだろうか

gunicorn とは

Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX.
*7 より抜粋

Gunicorn is a mature, fully featured server and process manager.

Uvicorn includes a Gunicorn worker class allowing you to run ASGI applications,
with all of Uvicorn's performance benefits, while also giving you
unicorn's fully-featured process management.
*2 より抜粋

  • gunicornは、 WSGIのHTTPサーバー
  • バージョン番号からも伺えるが、Gunicornは成熟している
  • UvicornWorkerをgunicornで使えば、Uvicornのパフォーマンスの恩恵を受けつつ、gunicornのプロセス管理などの機能が使える、といったところだろうか

Uvicorn のインストールと Hello, world

Uvicorn のインストール

pip install uvicorn

Uvicorn の Hello, world

  • uvicornを使ってWebサーバーを起動して、
  • HTTPリクエストに対して、
  • Hello, world と 環境変数 を返却する簡単な例
main.py
import uvicorn
import os

async def app(scope, receive, send):
    assert scope['type'] == 'http'

    mode = 'DEBUG'
    if ('MODE' in os.environ.keys()):
        mode = os.environ['MODE']

    body = (f'Hello, world (mode:{mode})\n').encode()

    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            [b'content-type', b'text/plain'],
        ],
    })
    await send({
        'type': 'http.response.body',
        'body': body,
    })

if __name__ == "__main__":
    uvicorn.run("main:app", host="127.0.0.1", port=8080, log_level="info")

unicornで、Webサーバーを起動

  • 以下のようにすると、フォアグランドで実行される
  • (nohup などを使って、バックグランド実行にすることもできる)
python main.py

INFO:     Started server process [49698]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
INFO:     127.0.0.1:45258 - "GET / HTTP/1.1" 200 OK

curlで動作確認

  • 環境変数が設定されていないので、モードがDEBUGと表示されることを確認
curl http://127.0.0.1:8080/

Hello, world (mode:DEBUG)

gunicornの活用

gunicorn のインストール

pip install gunicorn

gunicorn の起動

  • 先ほど作った Pythonのファイル名 main と 関数名appをgunicornのコマンドの引数に指定する
  • gunicornのコマンドオプションで各種設定が行える
  • ここでは、-c コマンドオプションのみを指定
  • -c を使うと、設定を外部ファイル(gunicorn_config.pyなど)に記述できる
# mainはpythonのファイル名、appは関数名

gunicorn -c gunicorn_config_prod.py main:app

gunicornの設定

  • ワーカー指定、デーモン化、プロセスIDをファイルに保存、プロセス名の指定ができる
  • (このあたりが、gunicornの特徴と考えてよいだろうか)
  • 設定の詳細は、*3が参考になる
gunicorn_config_prod.py

# 実行するPythonがあるパス
pythonpath = './'

# ワーカー数
workers = 2

# ワーカーのクラス、*2 にあるようにUvicornWorkerを指定 (Uvicornがインストールされている必要がある)
worker_class = 'uvicorn.workers.UvicornWorker'

# IPアドレスとポート
bind = '127.0.0.1:8080'

# プロセスIDを保存するファイル名
pidfile = 'prod.pid'

# Pythonアプリに渡す環境変数
raw_env = ['MODE=PROD']

# デーモン化する場合はTrue
daemon = True

# エラーログ
errorlog = './logs/error_log.txt'

# プロセスの名前
proc_name = 'my_python_app'

# アクセスログ
accesslog = './logs/access_log.txt'

動作確認

  • 設定した環境変数 PROD が表示されることを確認
curl http://127.0.0.1:8080/
Hello, world (mode:PROD)

gunicornのプロセスの確認

プロセス名を変更するためのパッケージをインストールする

pip install setproctitle

psコマンドでプロセスを確認

  • proc_name を設定しておくと、grepしやすい、みやすい
  • プロセス名を変更していない場合は、「gunicornという文字列」と「指定したport番号」などでgrepすればよさそう
  • (コマンドオプションでport番号を指定しておく必要があるが)
  • 以下のpsコマンドの実行で、masterプロセスが1つ、workerプロセスが2つあることが確認できる
  • gunicornの設定ファイルで指定したmy_python_appという名前が表示されることを確認
ps aux | grep my_python_app | grep -v grep

ubuntu     46752  0.1  2.2  33040 22608 ?        S    17:41   0:00 gunicorn: master [my_python_app]
ubuntu     46754  0.2  2.2  33512 22804 ?        S    17:41   0:00 gunicorn: worker [my_python_app]
ubuntu     46755  0.1  2.2  33512 22808 ?        S    17:41   0:00 gunicorn: worker [my_python_app]

gunicorn でプロセスIDをファイルに保存

  • 「pidfile」項目でファイル名のファイルにPIDが出力される
  • masterプロセスのPIDが保存されるようだ
prod.pid
cat prod.pid

46752
  • errorlog のINFOレベルのログでもプロセスIDを確認できそうだ
[2021-07-01 17:41:23 +0900] [46752] [INFO] Listening at: http://127.0.0.1:8080 (46752)
[2021-07-01 17:41:23 +0900] [46752] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2021-07-01 17:41:23 +0900] [46754] [INFO] Booting worker with pid: 46754
[2021-07-01 17:41:23 +0900] [46754] [INFO] Started server process [46754]
[2021-07-01 17:41:23 +0900] [46754] [INFO] Waiting for application startup.
[2021-07-01 17:41:23 +0900] [46754] [INFO] Application startup complete.
[2021-07-01 17:41:23 +0900] [46755] [INFO] Booting worker with pid: 46755
[2021-07-01 17:41:23 +0900] [46755] [INFO] Started server process [46755]
[2021-07-01 17:41:23 +0900] [46755] [INFO] Waiting for application startup.
[2021-07-01 17:41:23 +0900] [46755] [INFO] Application startup complete.

gunicorn のプロセスの停止

  • master プロセスを停止すれば、workerプロセスも停止するようだ

デーモン化したプロセスを停止するコマンド例

kill `cat prod.pid`

FastAPI

  • FastAPIを使った場合も同様に実行できた

FastAPIのインストール

pip install FastAPI
main2.py
import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

if __name__ == "__main__":
    uvicorn.run("main2:app", host="127.0.0.1", port=8080, log_level="info")

gunicorn -c gunicorn_config_prod.py main2:app

curl http://127.0.0.1:8080/
{"Hello":"World"}

参考資料

新規登録して、もっと便利にQiitaを使ってみよう

  1. あなたにマッチした記事をお届けします
  2. 便利な情報をあとで効率的に読み返せます
ログインすると使える機能について
hachicomb
記事の内容は個人の見解で、所属する組織の見解ではございません。
honeycomb-lab
様々なスキルを持つメンバーが、世の中の様々な課題やアイディアをクリエイティブとテクノロジーの力で解決し、ワクワクする未来の実現を目指します。xRコンテンツやインタラクティブコンテンツの企画・開発を得意とします。

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
新規登録
すでにアカウントを持っている方はログイン
14
どのような問題がありますか?
新規登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
新規登録ログイン
ストックするカテゴリー