Ubuntuとかでnginxのinitscript見るとstart-stop-daemon使ってデーモン化していて、デーモン化する手段として覚えておいた方が良さそうだなーと思ったので触ってみました。
以下、(俺が)挙動を理解する用のサンプル
#!/bin/bash
DAEMON=/usr/bin/python
PIDFILE=/home/xxx/hoge.pid
DAEMON_ARGS=/home/xxx/hoge.py
case "$1" in
"start")
start-stop-daemon --start --quiet --background --exec $DAEMON --make-pidfile --pidfile $PIDFILE -- $DAEMON_ARGS
result=$?
if [ $result != "0" ]
then
pid=`cat $PIDFILE`
echo "daemon is already running. (pid=${pid})"
exit 1
fi
;;
"stop")
start-stop-daemon --stop --quiet --pidfile $PIDFILE
result=$?
if [ $result != "0" ]
then
echo "daemon is not running. (check $PIDFILE)."
exit 1
fi
rm -f $PIDFILE
;;
esac
- –start:起動するときに使用
- –stop:停止するときに使用
- –background:デーモン化しないプログラムを実行するとき(フォアグラウンドプロセス)につける。これを指定するとforkしたりデーモン化するときのあれこれをやってくれる。
- –exec:実行するプログラム(–startasでもOK)
- –make-pidfile:start時にPIDファイルを生成するかどうかを指定(プログラム内で生成するのであれば指定しない)。stop時には自動的にPIDファイルを削除してくれないので自前でrmすることに注意する。
- –pidfile:PIDファイルのパスを指定
- –の後ろ:プログラムの引数
/usr/bin/python already running.
起動していないのに停止しようとすると
No process in pidfile '/home/tzm/hoge.pid' found running; none killed.
とメッセージが出力されます。
また、対象のPIDのプロセスが既に立ち上がってるかどうかは以下で確認可能です(戻り値が0であれば既に立ち上がっている状態) ```bash $ start-stop-daemon --stop --quiet --signal 0 --pidfile $pidfile ``` 以下の”標準出力をログに出力したい場合”でexec使う場合は、/bin/bashとexec先のプログラムが異なるので、startするたびに別のプロセスが生成されてしまいます。その場合は、上記コマンドを使って事前チェックで弾くか、--execではなく--startasを引数に利用することで二重起動を回避可能です(詳細は後述)。標準出力をログファイルに出力したい場合
以下のようにして標準出力をするためにexec+リダイレクトしてあげればOK。 ```bash $ start-stop-daemon --start --make-pidfile --pidfile $PIDFILE \ --background --exec /bin/bash -- -c \ "exec $DAEMON $DAEMON_ARGS >> /tmp/hoge.log 2>&1" ```デーモンはプロセスが端末と切り離されているので、通常のスクリプト実行とは挙動が異なる可能性があることに注意する必要があります。たとえばPythonだと通常のスクリプト実行と違い、標準出力やファイル出力がデフォルトでブロックバッファになります。
明示的に行バッファにするには
"exec stdbuf -oL -eL $DAEMON $DAEMON_ARGS >> /tmp/hoge.log 2>&1"
とするか、スクリプト内で明示的に行バッファを指定してファイル書き出しなどをすれば良いです。
Pythonの場合は、
open("/path/to/file.log", "w", 1)
とすればファイル書き出しは行バッファになり、標準出力の場合も色々と方法はあるみたいです。
–exec vs –startas
executableなscriptをデーモン化するときや、上記の標準出力をログファイルに出力するためにexecするようなケースにおいて、–execだと冪等性が確保できない(2回起動したら2つインスタンスが作成される)ので、startasを使うようです。startasはPIDだけで起動有無を確認する仕様らしいです。start-stop-daemon: –exec vs –startas - Chris Lamb
その他メモ
対象のPIDのプロセスがあるかどうかを確認[ ! -d /proc/$pid ]
実プロセスと実際のコマンドが有っているかの確認
$ cat /proc/$PID/cmdline | tr "\000" "\n"
おまけ(Upstart)
まぁこんな苦労しなくてもUpstart使えば一発です。description "test python daemon"
author "hoge <hoge@example.com>"
start on runlevel [2345]
stop on runlevel [016]
chdir /home/hoge
exec python ./fuga.py >> /var/log/fuga.log 2>&1
respawn
参考URL
- Manpage for start-stop-daemon - man.cx manual pages
- initscripts/ubuntu at master · Supervisor/initscripts
- Debian/Ubuntu Nginx init Script (opt) » KBeezie
- UbuntuでJavaアプリケーションをstart-stop-daemonを利用してデーモンにするには | hrendoh’s memo
- Upstart を使ってお手軽 daemon 化 - インフラエンジニアway - Powered by HEARTBEATS
- Getting Started - upstart