【Gunicorn】インストールから systemd での起動まで【Django】
はじめに
Django アプリケーションを本番環境で運用するにあたり、 WSGI サーバとして Gunicorn を使用する際の設定手順をまとめました。
本番運用には他にも Nginx などの Web サーバが必要ですが、今回は Gunicorn を systemd でサービス化し、 systemctl
コマンドで操作するところまでの説明です。
TL;DR
- 全部 Gunicorn の公式ドキュメントに載ってるよ
動作環境
OS | Version |
---|---|
CentOS | 7.7.1908 |
Language | Version |
---|---|
Python | 3.8.1 |
Application | Version |
---|---|
Gunicorn | 20.0.4 |
Django | 3.0.3 |
他の WSGI サーバとの比較
Gunicorn の他に、 Python Web アプリケーションで人気のある WSGI サーバとして、 uWSGI や Waitress などがあります。
今回初めて WSGI サーバを構築するので正しい評価ではないと思いますが、色々調べた結果、以下の理由で Gunicorn を選択しました。
- 他の WSGI サーバと比べて、シンプルな実装でサーバリソースが軽量である
- uWSGI の方が大幅にカスタマイズ可能で高機能だが、 Gunicorn も機能としては必要十分である
- 初めて WSGI サーバを構築するなら、手軽で利用事例も多い Gunicorn の方がおすすめ
Gunicorn のインストールと起動
インストール
1. PyPI からインストール
まずは、 Python の仮想環境下で pip で Gunicorn をインストールします。
今回は既に Django アプリケーションが作成済みの状態を想定しているので、カレントディレクトリは Django プロジェクトルートになります。
# 仮想環境をアクティベート . venv/bin/activate # Gunicorn をインストール pip install gunicorn
2. Gunicorn で Django をテスト起動
Gunicorn をインストールしたら gunicorn
コマンドで Django アプリケーションをテスト起動します。
gunicorn [Django Project Name].wsgi:application
Web ブラウザを起動して http://localhost:8000
を開き、 Django アプリケーションが表示されればインストールは成功です。
コマンド
Gunicorn は gunicorn
コマンドで起動します。
gunicorn コマンド
gunicorn [Options] $(MODULE_NAME):$(VARIABLE_NAME)
Target | Explanation |
---|---|
MODULE_NAME | WSGI モジュール名(カレントディレクトリからのドット付きフルパスで、拡張子は不要) |
VARIABLE_NAME | WSGI モジュール内の WSGI オブジェクト名 |
今回使用する主なオプションを以下にまとめました。
Options | Default Value | Explanation |
---|---|---|
-b $(HOST):$(PORT) , --bind $(HOST):$(PORT) |
127.0.0.1:8000 | バインドするサーバソケットを指定 |
-c $(PATH) , --config $(PATH) |
None | 設定ファイルのパスを指定 |
-e $(KEY)=$(VALUE) , --env $(KEY)=$(VALUE) |
[] | 環境変数の設定 |
-d , --daemon |
False | Gunicorn プロセスをデーモン化 |
設定ファイル
Gunicorn の設定ファイルは、拡張子付きの Python ソースファイルになります。
例えば、 gunicorn.conf.py
などです。
CLI で実行する gunicorn
コマンドのオプションと同様に、設定したいオプションと値を記述します。
import multiprocessing bind = "127.0.0.1:8000" daemon = True workers = multiprocessing.cpu_count() * 2 + 1
設定の優先順位
同じオプションに対して複数の設定が存在した場合、適用される値は優先度の高い順に
となります。
Django アプリケーションの起動
通常起動
起動
gunicorn [Django Project Name].wsgi:application
通常起動では Gunicorn 起動中はコンソールが専有され、常にログが表示されます。
開発時やテストを行う際に使用することが多いと思います。
停止
Ctrl + C
デーモン起動(バックグラウンド実行)
起動
gunicorn --daemon [Django Project Name].wsgi:application
本番運用時に手動で gunicorn
コマンドを実行する場合は、デーモンモードで起動することが主だと思います。
停止
プロセスを調べて kill
コマンドで停止します。
いちいちプロセスを調べて停止するのは面倒ですが、後述する systemd でサービス化を行えば systemctl
コマンドで起動・停止ができるようになります。
systemd による起動と停止
1. Unit 作成
systemd で Gunicorn を起動するための Unit を作成します。
service
と socket
の拡張子以外のファイル名は揃える必要があるので注意してください。
正直 Linux はあまり自信が無いので、 Gunicorn の 公式ドキュメント を参考にしましょう…
Service
/etc/systemd/system/gunicorn.service
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] Type=notify # the specific user that our service will run as User=[User Name] Group=[Group Name] RuntimeDirectory=gunicorn WorkingDirectory=[/ から Django Project Root までパス]/[Django Project Root] ExecStart=[/ から gunicorn コマンドまでのパス]/gunicorn --config gunicon.conf.py [Django Project Name].wsgi:application ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID KillMode=mixed TimeoutStopSec=5 PrivateTmp=true [Install] WantedBy=multi-user.target
ベースは Gunicorn の 公式ドキュメント にあったものを使用しています。
WorkingDirectory
と ExecStart
を対象の Django アプリケーションのパスに変更しましょう。
Socket
/etc/systemd/system/gunicorn.socket
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock # Our service won't need permissions for the socket, since it # inherits the file descriptor by socket activation # only the nginx daemon will need access to the socket # User=www-data # Optionally restrict the socket permissions even more. # Mode=600 [Install] WantedBy=sockets.target
こちらもベースは Gunicorn の 公式ドキュメント にあったものです。
特に変更点はありませんが、強いて言うなら User
くらいでしょうか。
2. Socket の起動
Unit を作成したら、 systemctl
コマンドで起動します。
systemctl
コマンドを使用する際は、ユーザの権限に応じて sudo
コマンドも併用してください。
systemctl enable --now gunicorn.socket
これで gunicorn.socket
で指定した /run/gunicorn.sock
にトラフィックが流れると、自動的に gunicorn.service
が起動されるようになります。
Gunicorn を systemd の Socket から起動する場合、監視している UNIX ドメインソケット(今回の例だと /run/gunicorn.sock
)へトラフィック流すように、 Web サーバ側で設定をする必要があります。
systemctl コマンド
起動 / 停止 / 再起動
# 起動 systemctl start gunicorn.socket # 停止 systemctl stop gunicorn.socket # 再起動 systemctl restart gunicorn.socket
自動起動
# 有効化 systemctl enable gunicorn.socket # 自動起動有効化と同時に起動 systemctl enable --now gunicorn.socket # 無効化 systemctl disable gunicorn.socket
状態確認
# gunicorn.socket の状態確認 systemctl status gunicorn.socket # gunicorn.service の状態確認 systemctl status gunicorn
3. 動作確認
curl
コマンドで、設定した UNIX ドメインソケットへリクエストを送信して動作を確認します。
curl --unix-socket /run/gunicorn.sock localhost
コンソール上に Django アプリケーションの HTML が表示されれば、 Gunicorn は正常に動作しています。
また、 systemctl status gunicorn
で gunicorn.service
の状態も確認しておきましょう。
おわりに
今回取り上げた Socket から Service を起動する方法の他に、 Service 単体で Gunicorn を常時起動しておき、 Web サーバから Gunicorn がバインドされているURI ( e.g. 127.0.0.1:8000
) へ転送する方法もあるようです。
ただ、Socket の使用有無について色々調べましたが、いまいちそれぞれのメリット・デメリットが分かりませんでした…
Gunicornの 公式ドキュメント には Socket からの起動方法が書かれていたので、今回は Socket 有の方法を紹介してみました。
どなたか詳しい方、systemd について分かりやすく教えてください!