24
25

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-07-02

経緯

  • 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"}

参考資料

24
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
25