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
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
unicorn master (old)
\_ unicorn master
 \_ unicorn worker[0]
 \_ unicorn worker[1]
 \_ unicorn worker[2]
 \_ unicorn worker[3]
  1. その後古いmasterプロセスにKILLシグナルを送信する。
1
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
#!/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
$ 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にご相談下さいませ!

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