付録C サーバ起動コマンド集

本付録では、Python Web アプリケーションを動かす代表的なサーバの起動コマンドを、開発用・本番用それぞれのパターンで紹介します。 付録 A・B で作成した最小アプリをそのまま使える形で示し、各オプションが「何を制御しているのか」を解説します。

注釈

本付録に登場するサーバは大きく WSGI 用ASGI 用の 2 種類に分かれます。

サーバ

対応プロトコル

主な用途

Gunicorn

WSGI(+ワーカー経由で ASGI も可)

Django・Flask の本番運用

uWSGI

WSGI

既存の運用実績がある環境

Uvicorn

ASGI

FastAPI・Starlette の開発〜本番

Gunicorn + UvicornWorker

ASGI

FastAPI・Starlette の本番運用(推奨)

どれを選ぶかは「アプリが WSGI か ASGI か」と「規模」によって決まります。


gunicorn

Gunicorn(Green Unicorn)は、WSGI アプリケーションのための本番グレードの HTTP サーバです。 pre-fork モデルを採用しており、マスタープロセスが複数のワーカープロセスを生成し、各ワーカーが独立してリクエストを処理します。

イメージとしては「親(マスター)が子(ワーカー)を監視し、子が止まったら新しい子を生む」仕組みです。

最小起動(開発確認用)

gunicorn app_hello:application

デフォルトでは 127.0.0.1:8000 にバインドし、ワーカー数は 1 です。 開発中の動作確認には十分ですが、本番ではワーカー数やタイムアウトの調整が必要になります。

本番向け起動

gunicorn app_json:application \
    --bind 0.0.0.0:8000 \
    --workers 4 \
    --threads 2 \
    --timeout 30 \
    --graceful-timeout 10 \
    --max-requests 1000 \
    --max-requests-jitter 50 \
    --access-logfile - \
    --error-logfile - \
    --log-level info

各オプションの意味は次のとおりです。

オプション

意味

--bind 0.0.0.0:8000

全インターフェースでリッスンします。リバースプロキシの背後に置く場合は UNIX ソケット(--bind unix:/run/gunicorn.sock)を使うとオーバーヘッドが減ります。

--workers 4

ワーカープロセス数です。目安は 2 × CPUコア数 + 1(2コアなら 5、4コアなら 9)です。

--threads 2

各ワーカー内のスレッド数です。IO バウンドな処理が多い場合に増やすと効果的です。ワーカー数 4 × スレッド数 2 で、同時に 8 リクエストを処理できます。

--timeout 30

ワーカーが 30 秒以内に応答しない場合にマスタープロセスが強制終了して再起動します。ハングしたワーカーの検出に使います。

--graceful-timeout 10

グレースフルシャットダウン(処理中のリクエストを完了させてから終了する)の猶予時間です。

--max-requests 1000

ワーカーが指定回数のリクエストを処理した後に自動再起動します。メモリリークの蓄積を防止できます。

--max-requests-jitter 50

max-requests にランダムなゆらぎを加え、全ワーカーが同時に再起動するのを防ぎます。

--access-logfile - / --error-logfile -

ログを標準出力に送ります。コンテナ環境では stdout / stderr に出力して外部のログ収集基盤に委ねるのが一般的です。

Tip

ワーカー数の目安 2 × CPUコア数 + 1 はあくまで出発点です。 CPU バウンドな処理(複雑な計算)が多いならコア数に合わせ、IO バウンドな処理(データベースやファイル待ち)が多いならスレッドを増やすほうが効果的な場合があります。 本番では負荷試験を行って最適値を探しましょう。

UNIX ソケットでの起動(nginx 連携)

gunicorn app_json:application \
    --bind unix:/run/gunicorn.sock \
    --workers 4 \
    --timeout 30

nginx 側では proxy_pass http://unix:/run/gunicorn.sock; で接続します。 TCP ソケットと比べてネットワークスタックを経由しないため、同一ホスト上ではパフォーマンスが向上し、ポート管理も不要になります。

設定ファイルを使った起動

オプションが増えるとコマンドラインが長くなるため、Python ファイルに設定をまとめることもできます。

# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
threads = 2
timeout = 30
graceful_timeout = 10
max_requests = 1000
max_requests_jitter = 50
accesslog = "-"
errorlog = "-"
loglevel = "info"
gunicorn app_json:application -c gunicorn.conf.py

便利な応用テクニック

設定ファイルは通常の Python コードとして実行されます。 そのため import multiprocessing して workers = multiprocessing.cpu_count() * 2 + 1 のように、CPU コア数に応じてワーカー数を動的に計算することも可能です。 環境ごとに設定を切り替えたい場合にも役立ちます。


uWSGI

uWSGI は多機能な WSGI/ASGI サーバで、Gunicorn より設定項目が多い分、細かな制御が可能です。 歴史的に広く使われてきましたが、近年は Gunicorn や Uvicorn を選択するプロジェクトが増えています。

注意

uWSGI プロジェクトは 2022 年頃にメンテナンスが停滞した時期があります。 新規プロジェクトへの導入前に、最新のメンテナンス状況を確認することをおすすめします。 既存の運用実績がある環境では引き続き利用できますが、これから始めるなら Gunicorn を選ぶのが無難です。

最小起動

uwsgi --http 127.0.0.1:8000 --wsgi-file app_hello.py --callable application

--http は uWSGI 自身が HTTP を話すモードです。nginx と連携する場合は --socket(uwsgi プロトコル)や --http-socket を使い分けます。

本番向け起動

uwsgi \
    --http-socket 0.0.0.0:8000 \
    --wsgi-file app_json.py \
    --callable application \
    --master \
    --processes 4 \
    --threads 2 \
    --harakiri 30 \
    --max-requests 1000 \
    --vacuum \
    --die-on-term \
    --stats 127.0.0.1:9191

Gunicorn と比較したときの特徴的なオプションを以下にまとめます。

オプション

意味

--master

マスタープロセスを有効にします。Gunicorn ではデフォルト ON ですが、uWSGI では明示的に指定が必要です。

--harakiri 30

Gunicorn の --timeout に相当します。指定秒数内に応答しないワーカーを強制終了します。

--vacuum

終了時にソケットファイルや pid ファイルを自動削除します。

--die-on-term

SIGTERM でクリーンに終了します。コンテナ環境で重要な設定です。

--stats 127.0.0.1:9191

リアルタイム統計を JSON で配信するエンドポイントです。uwsgitop ツールや監視システムと連携できます。

警告

--die-on-term は uWSGI 特有の落とし穴に対処するための設定です。 uWSGI はデフォルトで SIGTERM を「終了」ではなく「リロード」と解釈するという独自仕様があります。 この設定を忘れると、コンテナ(Docker など)が停止コマンドを送っても uWSGI が終了せず、コンテナが強制終了(SIGKILL)を待つことになります。 コンテナで uWSGI を使う場合は必ず指定しましょう。

INI ファイルによる設定

; uwsgi.ini
[uwsgi]
http-socket = 0.0.0.0:8000
wsgi-file = app_json.py
callable = application
master = true
processes = 4
threads = 2
harakiri = 30
max-requests = 1000
vacuum = true
die-on-term = true
uwsgi --ini uwsgi.ini

nginx との連携(uwsgi プロトコル)

uwsgi --socket /run/uwsgi.sock --wsgi-file app_json.py --callable application --master --processes 4

nginx 側では uwsgi_pass unix:/run/uwsgi.sock;include uwsgi_params; を設定します。 uwsgi プロトコルは HTTP より効率的なバイナリプロトコルで、nginx がネイティブにサポートしています。


uvicorn

Uvicorn は ASGI アプリケーションのための軽量・高速なサーバです。 内部で uvloop(libuv ベースのイベントループ)と httptools(Node.js の HTTP パーサーの Python バインディング)を使用しており、非同期処理に最適化されています。

最小起動(開発用)

uvicorn app_asgi:application --reload

--reload はファイル変更時の自動リロードを有効にします。 開発中は非常に便利な機能ですが、ファイルシステムの監視にリソースを使うため、本番環境では使ってはいけません。

警告

--reload開発専用 のオプションです。 本番環境で --reload を使うと、ファイルシステムの監視プロセスが常に走り続けてパフォーマンスが低下します。 また、アップロードされたファイルや設定ファイルが変更された際に意図せず再起動が発生するリスクもあります。 本番では必ず外してください。

本番向け起動

uvicorn app_asgi:application \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 4 \
    --loop uvloop \
    --http httptools \
    --no-access-log \
    --log-level warning

各オプションの補足です。

  • --workers 4: Uvicorn 0.17 以降で追加されたマルチワーカーモードです。内部的には Gunicorn と同様の pre-fork モデルを使います。

  • --loop uvloop: uvloop をイベントループとして使用します。uvloop がインストールされていない場合は asyncio のデフォルトループにフォールバックします。Linux / macOS で pip install uvloop しておくと、パフォーマンスが大幅に向上します(Windows では動作しません)。

  • --http httptools: HTTP パーサーとして httptools を使用します。ピュア Python 実装の h11 より高速です。

  • --no-access-log: アクセスログを無効にします。リバースプロキシ側でアクセスログを取っている場合、二重記録を防ぐために無効にすることがあります。

注釈

Uvicorn 単体の --workers は比較的新しい機能です。 Gunicorn のマスタープロセスが持つグレースフルリスタートやワーカー監視の成熟度には及ばない面があります。 小規模なデプロイであれば問題ありませんが、大規模な本番環境では次節の Gunicorn + UvicornWorker 構成を検討してください。


gunicorn + uvicorn worker

Gunicorn のプロセス管理能力と Uvicorn の ASGI 処理能力を組み合わせた構成です。 ASGI アプリケーションの本番デプロイにおける最も実績のある選択肢です。

「管理はベテランの Gunicorn に任せ、実際の仕事は速い Uvicorn がやる」という分業です。

基本の起動コマンド

gunicorn app_asgi:application \
    -k uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --workers 4 \
    --timeout 30 \
    --graceful-timeout 10 \
    --max-requests 1000 \
    --max-requests-jitter 50 \
    --access-logfile - \
    --error-logfile -

重要

-k uvicorn.workers.UvicornWorker がこの構成の核心です。 Gunicorn はデフォルトで同期 WSGI 用の sync ワーカーを使いますが、-k でワーカークラスを差し替えることで、各ワーカープロセス内で Uvicorn の ASGI イベントループが動作するようになります。

この構成の分業は次のとおりです。

  • Gunicorn(マスター): ワーカーの生成・監視・再起動・シグナルハンドリングを担当

  • Uvicorn(各ワーカー内): async な ASGI リクエスト処理を担当

UvicornWorkerUvicornH11Worker の違い

Uvicorn は 2 種類のワーカークラスを提供しています。

ワーカークラス

内部実装

用途

UvicornWorker

uvloop + httptools

本番環境で推奨される高速版

UvicornH11Worker

asyncio デフォルトループ + h11

uvloop が使えない環境やデバッグ時

# uvloop が使えない環境向け(Alpine Linux イメージなど)
gunicorn app_asgi:application \
    -k uvicorn.workers.UvicornH11Worker \
    --bind 0.0.0.0:8000 \
    --workers 4

設定ファイルとの組み合わせ

# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "uvicorn.workers.UvicornWorker"
timeout = 30
graceful_timeout = 10
max_requests = 1000
max_requests_jitter = 50
accesslog = "-"
errorlog = "-"
loglevel = "info"
gunicorn app_asgi:application -c gunicorn.conf.py

設定ファイル内で worker_class を指定すれば、コマンドラインの -k は不要になります。

FastAPI / Starlette との組み合わせ

FastAPI アプリケーションの場合、エントリポイントの指定は通常の Uvicorn と同様です。

gunicorn main:app \
    -k uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --workers 4

main:appmain.py 内の app = FastAPI(...) を指しています。


コマンド早見表

Tip

どのサーバを選べばよいか迷ったときは、この表を参考にしてください。

アプリの種類

環境

推奨サーバ

WSGI(Django・Flask)

本番

Gunicorn

WSGI(Django・Flask)

既存運用

uWSGI(既存設定を活かす場合)

ASGI(FastAPI・Starlette・Django ASGI)

本番(大規模)

Gunicorn + UvicornWorker

ASGI(FastAPI・Starlette)

本番(小規模)

Uvicorn 単体

WSGI / ASGI いずれも

開発中

--reload 付き Uvicorn または Django runserver

本付録で示した 4 つのサーバの使い分けをまとめると次のとおりです。

  • WSGI アプリ(Django・Flask)を本番で動かすなら Gunicorn が第一選択です。uWSGI は既存の運用実績がある場合に選択します。

  • ASGI アプリ(FastAPI・Starlette・Django ASGI)を本番で動かすなら Gunicorn + UvicornWorker が最も実績があります。小規模なら Uvicorn 単体でも十分です。

  • 開発時はいずれのフレームワークも --reload 付きの Uvicorn や Django の runserver で素早く確認し、本番では必ず上記のプロダクションサーバに切り替えましょう。

重要

どのサーバを選んでも、リバースプロキシ(nginx など)を前段に置くのが本番構成の基本です。 TLS 終端、静的ファイル配信、レート制限、バッファリングをリバースプロキシに任せることで、アプリケーションサーバは本来の仕事(リクエスト処理)に専念できます。

サーバの起動コマンドは「アプリケーションを動かす最後の一手」です。 その手前にある設計判断(ワーカー数・タイムアウト・プロセス管理)を理解したうえで選択することが重要です。