Unicornの自動起動設定

先日、OS起動時にUnicornが自動起動するよう設定する機会があり、その際にUnicornの停止や再起動についておさらいした覚え書きである。

前提

Unicornの停止方法

公式ドキュメントに記載されているが、要約する。

Unicornには停止用コマンドなどは用意されていない。Unicornはひとつのmasterプロセスと複数のworkerプロセスからなるが、masterプロセスにシグナルを送信することで停止できる。
送信シグナルによって以下の違いがある。

  • QUIT:gracefulな終了(workerの処理待ちをする。)
  • INT/TERM:強制終了(強制的にworkerプロセスをkillする。)

※一般的に、killコマンドでシグナル指定しなければTERMが送信され、Ctrl+Cでプロセスを止めればINTが送信されるが、INT/TERMのいずれでも停止処理は同じである。
http://bogomips.org/unicorn.git/tree/lib/unicorn/http_server.rb 参照。
なお、上記ソースは通常Unicornユーザは読む必要はないが、Unicornがどう動くかを勉強するのにはよい、とソース自体に書いてあった。

Unicornの再起動方法

Unicornは無停止再起動が可能であり、masterプロセスにHUPシグナルを送信すれば再起動するが、 preload_appフラグがONの場合にはアプリケーションの再ロードが走らないことに注意。ただし、
preload_appフラグがONでもアプリケーションの再ロードをしたい場合には以下のようにする。

  1. masterプロセスにUSR2シグナルを送信→新しいmaster, workerプロセスがforkされて以下のようなプロセスツリーとなる。
1
2
3
4
5
6
7
8
9
10
unicorn master (old)
\_ unicorn worker[0]
\_ unicorn worker[1]
\_ unicorn worker[2]
\_ unicorn worker[3]
\_ unicorn master
 \_ unicorn worker[0]
 \_ unicorn worker[1]
 \_ unicorn worker[2]
 \_ unicorn worker[3]
  1. 古いmasterプロセスにWINCHシグナルを送信し、古いworkerプロセスをgracefulに停止させる。
1
2
3
4
5
6
unicorn master (old)
\_ unicorn master
 \_ unicorn worker[0]
 \_ unicorn worker[1]
 \_ unicorn worker[2]
 \_ unicorn worker[3]
  1. その後古いmasterプロセスにKILLシグナルを送信する。
1
2
3
4
5
unicorn master
\_ unicorn worker[0]
\_ unicorn worker[1]
\_ unicorn worker[2]
\_ unicorn worker[3]

これでOK。
ただし、Unicornがデーモン化されていない場合はWINCHシグナルがスルーされるので、いったん停止してから起動する。(後述のスクリプトではデーモン想定でも停止、起動の流れにしてしまっている。)

自動起動設定

上記を踏まえて自動起動の設定をする。
/etc/init.d/に、例えば/etc/init.d/unicornファイルを作成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/bin/sh

#chkconfig:2345 85 70
#description:unicorn shell

NAME="Unicorn"
ENV=production

ROOT_DIR="/opt/rails/some_app/current"

GEMFILE="${ROOT_DIR}/Gemfile"
PID="${ROOT_DIR}/tmp/pids/unicorn.pid"
CONF="${ROOT_DIR}/config/unicorn.rb"
OPTIONS=""

start()
{
if [ -e $PID ]; then
echo "$NAME already started"
exit 1
fi
echo "start $NAME"
cd $ROOT_DIR
su - ec2-user -c "cd ${ROOT_RIR} && BUNDLE_GEMFILE=${GEMFILE} bundle exec unicorn -c ${CONF} -E ${ENV} -D ${OPTIONS}"
}

stop()
{
if [ ! -e $PID ]; then
echo "$NAME not started"
exit 1
fi
echo "stop $NAME"
kill -QUIT `cat ${PID}`
}

force_stop()
{
if [ ! -e $PID ]; then
echo "$NAME not started"
exit 1
fi
echo "stop $NAME"
kill -INT `cat ${PID}`
}

reload()
{
if [ ! -e $PID ]; then
echo "$NAME not started"
start
exit 0
fi
echo "reload $NAME"
kill -HUP `cat ${PID}`
}

restart()
{
stop
sleep 3
start
}

case "$1" in
start)
start
;;
stop)
stop
;;
force-stop)
force_stop
;;
reload)
reload
;;
restart)
restart
;;
*)
echo "Syntax Error: release [start|stop|force-stop|reload|restart]"
;;
esac
  • 上記スクリプトは http://tkoyama1988.hatenablog.com/entry/2014/09/15/175038 からほぼ流用させていただいた。
  • 上記スクリプトはAmazon Linux AMI release 2014.09で動作確認済み。
  • ランレベルはNginxと同様、停止起動順序はよろしく設定してください。
  • 各種ファイルパスもよろしく設定してください。

上記スクリプトで reload とした場合、Unicornのpreload_appフラグがONになっている場合はアプリケーションの再ロードは行われないことに注意。アプリケーションの再ロードをしたい場合にはrestartを指定する。

上記スクリプトをchkconfigで有効化し、適用されていることを確認。

1
2
3
4
5
6
7
8
9
$ sudo chkconfig unicorn on
$ chkconfig --list
acpid 0:off 1:off 2:on 3:on 4:on 5:on 6:off
atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off
...途中略
sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
td-agent 0:off 1:off 2:on 3:on 4:on 5:on 6:off
udev-post 0:off 1:on 2:on 3:on 4:on 5:on 6:off
unicorn 0:off 1:off 2:on 3:on 4:on 5:on 6:off

あとは、実際に検証して動くことをご確認ください。

Ruby on Railsを活用したWebサービスや業務システム開発をご検討の企業様は、是非MMMにご相談下さいませ!

このエントリーをはてなブックマークに追加