Python + responder + gunicorn + systemd + Nginx で Web アプリを起動する
以前に Python + falcon + gunicorn + systemd でシンプルな Web アプリを起動する というメモを書きました。 最近は responder が流行りらしいので、Python + responder + gunicorn + systemd + nginx 構成で「responder アプリケーションをデーモン化する」手順をメモしておきます。
今回の環境¶
今回は以下の環境を用いました。
- CentOS8
- pyenv をシステム全体にインストール済み
- Python 3.8.1
ライブラリのインストール¶
予め responder と gunicorn を pip でインストールしておきます。
アプリケーションの配置¶
アプリケーションを配置するディレクトリを作成します。 今回は /opt/hello としました。
アプリケーションとして /opt/hello/app.py を以下の内容で新規作成しました。
cat << EOF > /opt/hello/app.py
import responder
api = responder.API()
@api.route("/")
async def hello(req, resp):
resp.text = "hello, world!"
if __name__ == '__main__':
api.run()
EOF
アプリケーション実行用ユーザの作成¶
セキュリティを確保する為、このサービスは root ユーザでは無く、hello という専用ユーザで動作させることにします。 hello というシステムユーザを作成します。
今回の環境では UID / GID は以下になりました。
gunicorn の設定¶
今回は下記の内容で gunicorn 用の設定ファイルを用意します。 パラメータは環境に合わせて調整します。 responder は ASGI なのでワーカクラスには uvicorn.workers.UvicornWorker を指定します。
gunicorn を systemd 経由で起動する¶
まず先にこのサービスを識別する PID ファイルを作成しておきます。
systemd 経由で起動出来るよう、設定ファイルを用意します。
cat << EOF > /etc/systemd/system/hello.service
[Unit]
Description=Hello World!
Requires=hello.socket
After=network.target
[Service]
Type=notify
User=hello
Group=hello
RuntimeDirectory=gunicorn
WorkingDirectory=/opt/hello
ExecStart=/usr/local/pyenv/shims/gunicorn app:api --config settings.py
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
Nginx と gunicorn 間は UNIX ドメインソケットで通信させますので、ソケットファイルも用意しておきます。 www-data は Nginx インストール時に作成されるユーザです (この時点ではまだ Nginx をインストールしていない為、システム上に www-data ユーザは存在しません)。
cat << EOF > /etc/systemd/system/hello.socket
[Unit]
Description=hello socket
[Socket]
ListenStream=/run/hello.sock
User=www-data
[Install]
WantedBy=sockets.target
EOF
ソケットファイルを有効化しておきます。
systemd の設定を追加したので一度、設定を読み込み直します。
後は状態を確認しながらサービスを起動します。
systemctl status hello.service
systemctl start hello.service
systemctl enable hello.service
systemctl status hello.service
設定ファイルに間違いが無ければ gunicorn が起動するはずです。
Nginx のインストール¶
CentOS8 標準リポジトリ上の Nginx はバージョンが古いので、Nginx 公式リポジトリからインストールします。 Nginx リポジトリを追加します。
cat << EOF > /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
EOF
インストールします。 AppStream が優先されないよう、AppStream の無効化を明示的に指定してインストールします。
Nginx と gunicorn 間の通信設定¶
Nginx と gunicorn 間は UNIX ドメインソケットで通信させます。 今回は以下のように設定しました。
cat << EOF > /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name 127.0.0.1;
access_log /var/log/nginx/access.log main;
location / {
proxy_pass http://unix:/run/hello.sock;
}
}
EOF
Nginx の起動¶
後は Nginx の起動&自動起動をすれば完了です。
接続テスト¶
ローカルから接続テストを実行してみます。
問題なければリモートからブラウザで接続テストしてみます。
参考¶
/etc/nginx/conf.d/default.conf¶
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}