【Ubuntu】monit によるプロセス監視と Slack 通知

今回は monit の導入とプロセス再起動時に Slack に通知する方法についてです。

monit

monit は手軽にシステムリソースやファイルシステム, プロセスの監視とプロセス停止時に自動起動してくれるツール。ローカルホストだけでなくリモートホストに TCPやUDP, UNIXドメインソケットで接続して監視もできる。
今回はデーモンプロセスの監視に使うが, ファイルシステム監視をサポートしておりタイムスタンプやチェックサムの変更なども検知できる。

環境は Ubuntu 14.04.5 LTS, Monit 5.6 (古い…)

monit をインストールする。

$ sudo apt-get install monit
$ sudo monit -V
This is Monit version 5.6
Copyright (C) 2001-2013 Tildeslash Ltd. All Rights Reserved.

/etc/monit/conf.d/ 以下に監視プロセスごとの conf を書いていく。以下は mysql デーモンの監視設定で5サイクル内に5回停止検知・再起動した場合は監視対象から外れる設定。

$ sudo vim /etc/monit/conf.d/mysql.conf
check process mysql with pidfile /var/run/mysqld/mysqld.pid
  group database
  start program = "/etc/init.d/mysql start"
  stop program = "/etc/init.d/mysql stop"
  if failed host 127.0.0.1 port 3306 then restart
  if 5 restarts within 5 cycles then timeout

monit の設定ファイルを default のままで起動すると `monit: error connecting to the monit daemon` というエラーとなるため以下の部分をコメントアウト。

$ sudo vim /etc/monit/monitrc
...
set httpd port 2812 and
        use address localhost
        allow localhost
...

構文をチェックし monit を再起動する。

$ sudo monit -t
Control file syntax OK

$ sudo service monit restart
 * Restarting daemon monitor monit
   ...done.

実験で mysql デーモンを停止してみる。 monit status でプロセスの状態を確認すると Running から Does not exist となっていることがわかる。

$ sudo service mysql stop
...
 * MySQL Community Server 5.7.11 is stopped

monit のログに対象のプロセス停止を検知・その後起動を行なっていることを確認する。

$ tail -f /var/log/monit.log
...
[JST Jul 23 00:37:03] error    : 'mysql' process is not running
[JST Jul 23 00:37:03] info     : 'mysql' trying to restart
[JST Jul 23 00:37:03] info     : 'mysql' start: /bin/bash
[JST Jul 23 00:39:05] info     : 'mysql' process is running with pid 3517
...

mysql が起動していることを確認。

$ sudo service mysql status
mysql start/running, process 3517

Slack 通知

monit によりメンテナンスが楽になる一方, デーモンプロセスの停止はシステムの何らかの異常である可能性もあるため早めに認識したい。monit でメール送信も可能だけど Slack の方が気づき易いかもしれない。

monit によるプロセス再起動時に Slack に通知してみる。
最初に Slack で Incoming WebHooks の設定を行い Webhook URL を取得しておく。
次に mysql.conf の start program で /etc/init.d/mysql start が成功した時に実行する shell script を書く。 メッセージ部分は STDIN から受け取るようにする。

#!/bin/bash

set -eu

MESSAGEFILE=$(mktemp -t webhooks.XXXX)
trap "rm ${MESSAGEFILE}" 0

if [ -p /dev/stdin ]; then
    cat - | tr '\n' '\\' | sed 's/\\/\\n/g' > ${MESSAGEFILE}
else
    exit 1
fi

URL='https://hooks.slack.com/services/XXXXXXXX/XXXXXXXX/XXXXXXXXXXXXXXXXXXX'
CHANNEL=${CHANNEL:-'#monitoring_test'}
BOTNAME=${BOTNAME:-'monitoring-bot'}

payload="payload={
    \"channel\": \"${CHANNEL}\",
    \"username\": \"${BOTNAME}\",
    \"text\": \"${MESSAGE}\"
}"

curl -s -S -X POST --data-urlencode "${payload}" ${URL} > /dev/null

最後に mysql.conf を以下のように変更し設定変更を適用する。 exec を使う方法もある。

$ sudo vim /etc/monit/conf.d/mysql.conf
check process mysql with pidfile /var/run/mysqld/mysqld.pid
  group database
  start program = "/bin/bash -c '/etc/init.d/mysql start && /bin/echo restart mysql at `/bin/date +"%Y-%m-%dT%H:%M:%S"` by monit | ./path/to/your/notify_slack.sh'"
  stop program = "/etc/init.d/mysql stop"
  if failed host 127.0.0.1 port 3306 then restart
  if 5 restarts within 5 cycles then timeout

おわりに

今回は monit から Incoming WebHooks 経由で Slack へ通知する方法として, 環境依存性の低い shell script を選択しました。
他にも Python アプリケーション内から Slack へ通知する場合に slackweb を使ってみましたがこちらも簡単にできました。


[1] LEMP Stack Monitoring with Monit on Ubuntu 14.04
[2] シェルスクリプトでSlackに通知を送る方法
[3] Monit and multiple actions: chaining commands in Monit restart command?
[4] Amazon Linuxでmonitを使ってカジュアルにプロセス監視する!