production.log

株式会社リブセンスでエンジニアをやっている星直史のブログです。

SnapmartのWebサーバーにmonitを導入してunicornを不死鳥にした

概要

Webサービスを運営していると、夜中にWebサーバーのプロセスが突然死してしまい、朝に気づくということが多々あります。
流石に人間が24時間365日監視しているのはツラいので、ある特定のプロセスが落ちたら自動で検知と再起動という処理を行いたいです。
今回はSnapmartのWebサーバーにmonitを導入してunicornを不死鳥にしたので、その導入について書きます。

monitとは

冒頭でも述べましたが、ざっくりいうとmonitはサーバーのある特定のプロセスを監視し、プロセスがなくなったことを検知、自動再起動を行うOSSです。 monitが監視する条件に合致した場合に再起動を行うだけなので、原因の根本解決などは人間が行う必要があります。

導入手順

手順は大きく4つあります。

  1. monitをinstall
  2. unicornの起動スクリプトを書く
  3. unicorn用のmonitの設定を記述
  4. monitの再起動と動作確認

monitをinstall

monitはyumでinstallすることができます。

sudo yum install monit

unicornの起動スクリプトを書く

monitが自動で再起動させるためのスクリプトを書きます。 このスクリプトは/etc/init.d/unicornに配置します。 スクリプトの内容は下記の通りです。

#!/bin/sh
NAME="Unicorn"
ENV=production

RAILS_DIR="/awesome_your_app"
PID="${RAILS_DIR}/log/unicorn/unicorn.pid"
CONF="${RAILS_DIR}/config/unicorn.rb"

start()
{
    if [ -e $PID ]; then
        echo "already started"
        exit 1
    fi
    echo "start unicorn"
    su - ec2-user -c "cd ${RAILS_DIR} && bundle exec unicorn_rails -c ${CONF} -E ${ENV} -D"
}
stop()
{
    if [ ! -e $PID ]; then
        echo "${NAME} already stopped"
        exit 1
    fi
    echo "stop ${NAME}"
    kill -QUIT `cat ${PID}`
}

restart()
{
    stop
    sleep 3
    start
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    *)
    echo "Syntax Error"
    exit 2
    ;;
esac

上記のファイルを作成すると、/etc/init.d/unicorn start|stop|restartを行うことができます。 これを用いてmonitがプロセスの再起動を行うわけです。
※併せてchkconfigを設定するのも良いと思います。今回は割愛

unicorn用のmonitの設定を記述

monit.conf

まずmonit自体の設定を行います。設定ファイルは/etc/monit.confです。
こちらのファイルで重要なのは、Include /etc/monit.d/*.monitrcです。 これは、/etc/monit.d/配下にある*.monitrcをIncludeする設定です。この設定を行い、特定のモジュールに限定した設定ファイルを用意することで、管理が容易になります。

set daemon 60
set mailserver localhost
set eventqueue
    basedir /var/monit
    slots 100
set logfile syslog
Include /etc/monit.d/*.monitrc
Include /etc/monit.d/logging
set httpd port 2812 and use the address localhost
  allow localhost

/etc/monit.d/unicorn.monitrc

続いて、monitのunicorn監視用の設定を書いていきます。

check process unicorn with pidfile /awesome_your_app/log/unicorn/unicorn.pid
  group ec2-user
  start program = "/etc/init.d/unicorn restart"
  stop program = "/etc/init.d/unicorn stop"
  if 5 restarts within 5 cycles then unmonitor

設定はとてもシンプルです。

  • start, stopをどのgroupで、どのコマンドを実行するか
  • 何サイクルで何度失敗したら監視をやめるかを設定しています。

monitの再起動と動作確認

monitの再起動

これまでの設定を再読み込みしたいので、monitを再起動します。

sudo monit reload

動作確認

最後に動作確認をします。

  • monitがunicornプロセスを監視しているのか
  • unicornプロセスが落ちた場合に自動で再起動するか

上記2点が満たされれば良しとします。

monitがunicornプロセスを監視しているのか

monitの状況はsudo monit statusコマンドで確認できます。

Process 'unicorn'
  status                            running
  monitoring status                 monitored
  pid                               3941
  parent pid                        1
  uptime                            5h 0m 
  children                          5
  memory kilobytes                  204080
  memory kilobytes total            1670284
  memory percent                    5.3%
  memory percent total              44.0%
  cpu percent                       0.0%
  cpu percent total                 0.0%
  data collected                    Thu May 23 04:08:47 2019

バッチリですね!

unicornプロセスが落ちた場合に自動で再起動するか

monitのログを確認するために、sudo tail -f /var/log/monitでログを見守ります。 別のプロセスで/etc/init.d/unicorn stopを行います。

[UTC May 23 00:59:41] error    : 'unicorn' process is not running
[UTC May 23 00:59:41] info     : 'unicorn' trying to restart
[UTC May 23 00:59:41] info     : 'unicorn' start: /etc/init.d/unicorn
[UTC May 23 01:00:42] info     : 'unicorn' process is running with pid 20241

1分ほどすると上記のようにログが出てきます。

  • unicorn プロセスが実行されていないことを検知
  • unicorn プロセスを起動させようと試みる
  • /etc/init.d/unicornを実行
  • PID: 20241でunicornが起動

といった具合で自動で起動されました。バッチリですね!

まとめ

今回は、monitを導入してunicornプロセスが落ちた場合に自動で再起動されるようにしました。
unicornだけではなく、nginxやpostfixといったミドルウェアが謎の変死を遂げるのであれば、monitの導入を考えても良いでしょう。

また、monitを導入すると、導入の背景にあった人間が24時間365日監視を行うということから解放されます。
心配が一つ減るのは良いですね。

ただ、monitで再起動がかかるのは良いのですが、根本の原因は解決しなければなりません。
運用の負担はどんどん減らしていきましょう。