gunicornをsystemdで動かした
gunicorn(19.9)をsystemdで動かした場合に色々と嵌ったのでメモ。
https://github.com/benoitc/gunicorn/blob/master/docs/source/deploy.rst#systemd
最終的に動いた設定
/etc/systemd/system/app.socket:
[Unit] Description=gunicorn app socket [Socket] ListenStream=/run/app.sock User={{ app_user }} Group={{ app_group }} [Install] WantedBy=sockets.target
/etc/systemd/system/app.service:
[Unit] Description=gunicorn app service Requires=app.socket After=network.target [Service] PIDFile=/run/gunicorn/app.pid RuntimeDirectory=gunicorn User={{ app_user }} Group={{ app_group }} ExecStart=/path/to/venv/bin/gunicorn \ --workers 2 \ --pid /run/gunicorn/app.pid \ --access-logfile /var/log/app/access.log \ --error-logfile /var/log/app/error.log \ --capture-output \ --log-level info \ app.wsgi:application ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
どこにはまったかのか
まず公式のドキュメント通りに動かなかった。なんかソケットが消えてしまう。
https://github.com/benoitc/gunicorn/issues/1524
を見る感じドキュメントを更新したとのことでmasterのドキュメントを参考にしてみた。
これが良くなかったんだけども。
こんな感じにpidの指定はいらないのか−と思ってたりType=notify
ってなに?🤔と思いつつ設定してみた。
[Unit] Description=gunicorn app service Requires=app.socket After=network.target [Service] Type=notify User={{ app_user }} Group={{ app_group }} ExecStart=/path/to/venv/bin/gunicorn \ --workers 2 \ --access-logfile /var/log/app/access.log \ --error-logfile /var/log/app/error.log \ --capture-output \ --log-level info \ app.wsgi:application ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStartSec=5 PrivateTmp=true [Install] WantedBy=multi-user.target
アプリは立ち上がるんだけどもapp.serviceのステータスがloadedのままで90秒で強制的にプロセスが終了。
なんで終了されるのかは、Type=notify
の場合はコード側で起動した事を知らせる必要があるみたいなんだけど、そもそも19.9とmasterではコードが異なってたので19.9ではその処理が入って無かった。
https://github.com/benoitc/gunicorn/blob/19.9.0/gunicorn/systemd.py
https://github.com/benoitc/gunicorn/blob/master/gunicorn/systemd.py
90秒で強制的に終了するというのは
1.リクエストが来る=>2.起動してなければ起動する=>1から90秒立つ=>落ちる=>1に戻る
なのでリクエストが来るたびに起動はするので動いてるようには見えるんだけど、処理のかかるリクエストだと途中で処理が終わって404が返ってきた。
初期データのcsvインポートが大量にあったので気づいたんだけども。
最終的にはapp.serviceをstopしてもリクエストを投げたタイミングで起動してactiveになって強制終了されることはなくなった。
結果として
- 19.9ではpidの指定が必要 gunicornにbindの指定は不要
- masterブランチではpidの指定は不要 gunicornにbindの指定は不要(多分)
に至ったんだけどもgunicorn次はいつリリースされるんだろう...
nginx
location / { proxy_pass http://unix:/run/app.sock; }
systemdの知識が少し深まったけどsocketの知識も深めないと...