# 付録C サーバ起動コマンド集 本付録では、Python Web アプリケーションを動かす代表的なサーバの起動コマンドを、開発用・本番用それぞれのパターンで紹介します。 付録 A・B で作成した最小アプリをそのまま使える形で示し、各オプションが「何を制御しているのか」を解説します。 ```{note} 本付録に登場するサーバは大きく **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 モデル**を採用しており、マスタープロセスが複数のワーカープロセスを生成し、各ワーカーが独立してリクエストを処理します。 > イメージとしては「親(マスター)が子(ワーカー)を監視し、子が止まったら新しい子を生む」仕組みです。 **最小起動(開発確認用)** ```bash gunicorn app_hello:application ``` デフォルトでは `127.0.0.1:8000` にバインドし、ワーカー数は 1 です。 開発中の動作確認には十分ですが、本番ではワーカー数やタイムアウトの調整が必要になります。 **本番向け起動** ```bash 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 連携)** ```bash gunicorn app_json:application \ --bind unix:/run/gunicorn.sock \ --workers 4 \ --timeout 30 ``` nginx 側では `proxy_pass http://unix:/run/gunicorn.sock;` で接続します。 TCP ソケットと比べてネットワークスタックを経由しないため、同一ホスト上ではパフォーマンスが向上し、ポート管理も不要になります。 **設定ファイルを使った起動** オプションが増えるとコマンドラインが長くなるため、Python ファイルに設定をまとめることもできます。 ```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" ``` ```bash gunicorn app_json:application -c gunicorn.conf.py ``` ```{admonition} 便利な応用テクニック 設定ファイルは通常の Python コードとして実行されます。 そのため `import multiprocessing` して `workers = multiprocessing.cpu_count() * 2 + 1` のように、CPU コア数に応じてワーカー数を動的に計算することも可能です。 環境ごとに設定を切り替えたい場合にも役立ちます。 ``` --- ## uWSGI uWSGI は多機能な WSGI/ASGI サーバで、Gunicorn より設定項目が多い分、細かな制御が可能です。 歴史的に広く使われてきましたが、近年は Gunicorn や Uvicorn を選択するプロジェクトが増えています。 ```{caution} uWSGI プロジェクトは 2022 年頃にメンテナンスが停滞した時期があります。 新規プロジェクトへの導入前に、最新のメンテナンス状況を確認することをおすすめします。 既存の運用実績がある環境では引き続き利用できますが、これから始めるなら Gunicorn を選ぶのが無難です。 ``` **最小起動** ```bash uwsgi --http 127.0.0.1:8000 --wsgi-file app_hello.py --callable application ``` `--http` は uWSGI 自身が HTTP を話すモードです。nginx と連携する場合は `--socket`(uwsgi プロトコル)や `--http-socket` を使い分けます。 **本番向け起動** ```bash 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` ツールや監視システムと連携できます。 | ```{warning} `--die-on-term` は uWSGI 特有の落とし穴に対処するための設定です。 uWSGI はデフォルトで SIGTERM を「終了」ではなく「リロード」と解釈するという独自仕様があります。 この設定を忘れると、コンテナ(Docker など)が停止コマンドを送っても uWSGI が終了せず、コンテナが強制終了(SIGKILL)を待つことになります。 コンテナで uWSGI を使う場合は必ず指定しましょう。 ``` **INI ファイルによる設定** ```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 ``` ```bash uwsgi --ini uwsgi.ini ``` **nginx との連携(uwsgi プロトコル)** ```bash 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 バインディング)を使用しており、非同期処理に最適化されています。 **最小起動(開発用)** ```bash uvicorn app_asgi:application --reload ``` `--reload` はファイル変更時の自動リロードを有効にします。 開発中は非常に便利な機能ですが、ファイルシステムの監視にリソースを使うため、本番環境では使ってはいけません。 ```{warning} `--reload` は **開発専用** のオプションです。 本番環境で `--reload` を使うと、ファイルシステムの監視プロセスが常に走り続けてパフォーマンスが低下します。 また、アップロードされたファイルや設定ファイルが変更された際に意図せず再起動が発生するリスクもあります。 本番では必ず外してください。 ``` **本番向け起動** ```bash 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`: アクセスログを無効にします。リバースプロキシ側でアクセスログを取っている場合、二重記録を防ぐために無効にすることがあります。 ```{note} Uvicorn 単体の `--workers` は比較的新しい機能です。 Gunicorn のマスタープロセスが持つグレースフルリスタートやワーカー監視の成熟度には及ばない面があります。 小規模なデプロイであれば問題ありませんが、大規模な本番環境では次節の **Gunicorn + UvicornWorker 構成**を検討してください。 ``` --- ## gunicorn + uvicorn worker Gunicorn のプロセス管理能力と Uvicorn の ASGI 処理能力を組み合わせた構成です。 ASGI アプリケーションの本番デプロイにおける最も実績のある選択肢です。 > 「管理はベテランの Gunicorn に任せ、実際の仕事は速い Uvicorn がやる」という分業です。 **基本の起動コマンド** ```bash 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 - ``` ```{important} `-k uvicorn.workers.UvicornWorker` がこの構成の核心です。 Gunicorn はデフォルトで同期 WSGI 用の `sync` ワーカーを使いますが、`-k` でワーカークラスを差し替えることで、各ワーカープロセス内で Uvicorn の ASGI イベントループが動作するようになります。 この構成の分業は次のとおりです。 - **Gunicorn(マスター)**: ワーカーの生成・監視・再起動・シグナルハンドリングを担当 - **Uvicorn(各ワーカー内)**: `async` な ASGI リクエスト処理を担当 ``` **`UvicornWorker` と `UvicornH11Worker` の違い** Uvicorn は 2 種類のワーカークラスを提供しています。 | ワーカークラス | 内部実装 | 用途 | |---|---|---| | `UvicornWorker` | `uvloop` + `httptools` | 本番環境で推奨される高速版 | | `UvicornH11Worker` | `asyncio` デフォルトループ + `h11` | `uvloop` が使えない環境やデバッグ時 | ```bash # uvloop が使えない環境向け(Alpine Linux イメージなど) gunicorn app_asgi:application \ -k uvicorn.workers.UvicornH11Worker \ --bind 0.0.0.0:8000 \ --workers 4 ``` **設定ファイルとの組み合わせ** ```python # 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" ``` ```bash gunicorn app_asgi:application -c gunicorn.conf.py ``` 設定ファイル内で `worker_class` を指定すれば、コマンドラインの `-k` は不要になります。 **FastAPI / Starlette との組み合わせ** FastAPI アプリケーションの場合、エントリポイントの指定は通常の Uvicorn と同様です。 ```bash gunicorn main:app \ -k uvicorn.workers.UvicornWorker \ --bind 0.0.0.0:8000 \ --workers 4 ``` `main:app` は `main.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` で素早く確認し、本番では必ず上記のプロダクションサーバに切り替えましょう。 ```{important} どのサーバを選んでも、**リバースプロキシ(nginx など)を前段に置く**のが本番構成の基本です。 TLS 終端、静的ファイル配信、レート制限、バッファリングをリバースプロキシに任せることで、アプリケーションサーバは本来の仕事(リクエスト処理)に専念できます。 サーバの起動コマンドは「アプリケーションを動かす最後の一手」です。 その手前にある設計判断(ワーカー数・タイムアウト・プロセス管理)を理解したうえで選択することが重要です。 ```