systemctl start でサービス起動したのに、OOM killer などによってプロセスが殺されたりすることは往々にあると思いますが、プロセスの死活監視をしてないと対策が遅れてしまうことがあります。 そこで、systemd の Restart を使ってプロセスの再起動を自動でやらせたいと思います。
systemd の Unit ファイルの [Service] のセクションでは Restart という設定項目があり1、これを使うことでプロセスが勝手に終了しても自動でプロセスを再起動させることができます。 なお、systemctl stop のように systemd のコマンドを使って終了させた場合は再起動しません。
Restartの値は no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always のいずれかです。 基本的には always で十分だと思います。
no | always | on-success | on-failure | on-abnormal | on-abort | on-watchdog | |
---|---|---|---|---|---|---|---|
Clean exit code or signal | O | O | |||||
Unclean exit code | O | O | |||||
Unclean signal | O | O | O | O | |||
Timeout | O | O | O | ||||
Watchdog | O | O | O | O |
- no : プロセスが終了してもプロセスを再起動しません。
- on-success : プロセスが正常終了したときにプロセスを再起動します。ただし正常終了とは終了コードが 0 のときや SIGHUP, SIGINT, SIGTERM, SIGPIPE のシグナルで終了した場合のことです。
- on-failure : プロセスが異常終了したときにプロセスを再起動します。ただし異常終了とは終了コードが 0 以外のときやコアダンプなどの上記4つ以外のシグナルで終了した場合などのことです。
- on-abnormal : on-failure と似ていますが、終了コードによるプロセスの再起動はしません。
- on-abort : プロセスが上記4つ以外のシグナルで終了したときにプロセスを再起動します。
- on-watchdog : watchdogがタイムアウトしたときにプロセスを再起動します。
なお、短い時間で何回も再起動が発生すると再起動を諦める機能があります2。 具体的には StartLimitInterval の間に StartLimitBurst の回数だけ再起動が起きると、systemd は自動的に再起動するのを止めます。デフォルトでは 10 秒の間に 5 回まで再起動が行われ、それを超えると再起動を諦めます。
デフォルト値は /etc/systemd/system.conf に書かれています。
[Manager]
...
#DefaultStartLimitInterval=10s
#DefaultStartLimitBurst=5
...
サンプルアプリでプロセス自動再起動
例えば、以前作成した簡易Webサーバを例にプロセスの再起動を確認してみたいと思います。
まず作成した必要なファイルは以下の通りです。
再起動は Restart=always
としています。
/etc/systemd/system/tinyhttpd
[Unit]
Description=Tiny HTTPD
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python /usr/local/bin/tinyhttpd.py
Restart=always
[Install]
WantedBy=multi-user.target
/usr/local/bin/tinyhttpd.py
#!/usr/bin/env python
import os
import sys
import SimpleHTTPServer
import SocketServer
if __name__ == "__main__":
out = sys.stderr
host = os.getenv("TINYHTTPD_HOST", "")
port = os.getenv("TINYHTTPD_PORT", 8000)
listen = (str(host), port)
SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.TCPServer(
listen,
SimpleHTTPServer.SimpleHTTPRequestHandler,
)
out.write("listen: host=%s, port=%s\n" % (host, port))
httpd.serve_forever()
systemctlをリロードして、Webサーバを起動します。
# systemctl daemon-reload
# systemctl start tinyhttpd
curlで叩いてアクセスできることを確認。
# curl localhost:8000
次に ps auxw
で python プロセスを確認したら kill <PID>
で当該プロセスを殺します。
プロセスIDがわからなければ pkill を使ってもOKです。
# pkill -f '/usr/bin/python /usr/local/bin/tinyhttpd.py'
そしたら systemd のログは /var/log/messages に書かれているので、tail -f で開いて中身を確認します。
# tailf /var/log/messages
一番下に、プロセスが終了したこととプロセス再起動したことがログにあれば、自動的にプロセスが再起動したことが確認できます。
Mar 8 10:11:12 localhost systemd: tinyhttpd.service holdoff time over, scheduling restart.
Mar 8 10:11:12 localhost systemd: Started Tiny HTTPD.
Mar 8 10:11:12 localhost systemd: Starting Tiny HTTPD...
Mar 8 10:11:12 localhost python: listen: host=, port=8000
自動で再起動した状態なら、再度 curl で叩いてもアクセスできます。
# curl localhost:8000
ps auxw
で確認すると python プロセスの PID も変わっていることも確認できます。