ども、2015 年も Slack of the year の cloudpack の かっぱ (@inokara) です。
はじめに
Monit って alert オプションでメールを飛ばすことが出来ますが Slack に飛ばせないかなって思ってぐぐったら以下のような先人の知恵がアップされていました。
有難い。
先人に負けじと
試してみました。
環境
# cat /etc/system-release Amazon Linux AMI release 2014.09 # monit -V This is Monit version 5.2.5 Copyright (C) 2000-2011 Tildeslash Ltd. All Rights Reserved.
monit のインストールについては割愛します。
監視対象
何の変哲も無い Apache のプロセス名(httpd
)を監視します。
check process httpd with matching "httpd" start program = "/etc/init.d/httpd start" stop program = "/etc/init.d/httpd stop" if does not exist then exec "/opt/bin/post_to_slack.rb" else if succeeded for 1 cycle then exec "/opt/bin/post_to_slack.rb" group https
上記の設定では httpd
という名前のプロセス名が存在しているか否かを監視しています。もし does not exist
の場合には exec
コマンドにて任意のスクリプト(/opt/bin/post_to_slack.rb
)が実行されます。今回のキモは exec
です。
monit は上記例のプロセス名のチェック以外にも PID
ファイルの有無や任意のコマンドの実行結果でアクション(通知、プロセスの再起動)を行うことが可能です。
詳細は上記のドキュメントをご確認ください。
ザクッと以下の通り。
- EXISTENCE TESTING
- RESOURCE TESTING
- FILE CHECKSUM TESTING
- TIMESTAMP TESTING
- FILE SIZE TESTING
- FILE CONTENT TESTING
- FILESYSTEM FLAGS TESTING
- SPACE TESTING
- INODE TESTING
- PERMISSION TESTING
- UID TESTING
- GID TESTING
- PID TESTING
- PPID TESTING
- PROCESS UPTIME TESTING
- PROGRAM STATUS TESTING
- NETWORK LINK STATUS TEST
- NETWORK LINK CAPACITY TEST
- NETWORK SATURATION TEST
- NETWORK BANDWIDTH TEST
- NETWORK PACKETS TEST
- NETWORK PING TEST
- CONNECTION TESTING
それぞれのテストに対してどのようなアクションが行われるかについては以下のコマンドにて確認することが出来ます。
/usr/bin/monit -vI
以下のように出力されます。
Runtime constants: Control file = /etc/monit.conf Log file = /var/log/monit Pid file = /var/run/monit.pid Debug = True Log = True Use syslog = False Is Daemon = True Use process engine = True Poll time = 60 seconds with start delay 0 seconds Expect buffer = 256 bytes Mail from = (not defined) Mail subject = (not defined) Mail message = (not defined) Start monit httpd = False The service list contains the following entries: Process Name = httpd Group = httpd Match = httpd Monitoring mode = active Start program = '/etc/init.d/httpd start' timeout 30 second(s) Stop program = '/etc/init.d/httpd stop' timeout 30 second(s) Existence = if does not exist 1 times within 1 cycle(s) then exec '/opt/bin/post_to_slack.rb' timeout 0 cycle(s) else if succeeded 1 times within 1 cycle(s) then exec '/opt/bin/post_to_slack.rb' timeout 0 cycle(s) Pid = if changed 1 times within 1 cycle(s) then alert Ppid = if changed 1 times within 1 cycle(s) then alert System Name = system_ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal Monitoring mode = active ------------------------------------------------------------------------------- monit daemon at 25226 awakened
上記の例では Existence
チェックのアクションは Slack への通知スクリプトが実行されます。また、Pid
チェックについては alert
とありますので alert
で定義されたメール通知が行われます。
(追記)
ちなみに alert
オプションはメール通知のみですが、メール以外が利用出来るといいような気がします。上記の参考記事以外にも HipChat への通知方法も掲載されていますが、あくまでも exec
オプションを利用しての通知となります。尚、試した範囲では exec
を利用した場合には「通知した後で restart
のような事が monit 単体では出来ない」点が残念な感じでした。
Slack 通知スクリプト
Slack の API を叩く Ruby のスクリプトを以下のように作成します。
#!/usr/bin/env ruby require 'net/https' require 'json' uri = URI.parse("https://hooks.slack.com/services/xxxxxxx/yyyyyyyyy/zzzzzzzzzzzzzzzzzzzzzzzzz") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri.request_uri, {'Content-Type' => 'application/json'}) request.body = { "channel" => "#notify-monit", "username" => "monit", "text" => "[#{ENV['MONIT_HOST']}] #{ENV['MONIT_SERVICE']} - #{ENV['MONIT_DESCRIPTION']}", "icon_emoji" => ":icon:" }.to_json response = http.request(request) puts response.body # restart process if ENV['MONIT_DESCRIPTION'].include?("not") system("/etc/init.d/httpd restart") end
API は Body に JSON で以下のような情報を付加します。
request.body = { "channel" => "#notify-monit", "username" => "monit", "text" => "[#{ENV['MONIT_HOST']}] #{ENV['MONIT_SERVICE']} - #{ENV['MONIT_DESCRIPTION']}", "icon_emoji" => ":icon:" }.to_json
上記の例では #{ENV['MONIT_HOST']}
には monit が稼働されるホスト名が入ります。また、#{ENV['MONIT_SERVICE']}
や #{ENV['MONIT_DESCRIPTION']}
には監視するサービスや詳細が入ります。以下は SlackAPI ドキュメントの一部です。
今回は利用していませんが attachments
を利用すれば詳細な情報も通知に含めることが出来そうです。 尚、今回は参考にさせて頂いたサイトに倣って Ruby で作りましたが JSON が生成出来れば bash 等でも実装かと思います。
試す
monit が起動した状態で Apache を止めてみましょう。
$ sudo /etc/init.d/monit start $ sudo /etc/init.d/monit status monit (pid 25226) is running... $ sudo /etc/init.d/http stop Stopping httpd: [ OK ]
念の為に monit のログを確認しましょう。
[UTC Jan 6 14:56:31] error : 'httpd' process is not running [UTC Jan 6 14:56:31] info : 'httpd' exec: /opt/bin/post_to_slack.rb
post_to_slack.rb
が実行されたのが判ります。また、再起動も自動で行われる為、しばらくすると以下のように出力されます。
[UTC Jan 6 14:57:31] info : 'httpd' process is running with pid 25753 [UTC Jan 6 14:57:31] info : 'httpd' exec: /opt/bin/post_to_slack.rb
再起動が行われ、プロセスが稼働していることも検知されて通知も合わせ行われます。
Slack には以下のように通知が行われています。
おお、ちゃんと通知が。
monit おもろい
CONNECTION TESTING
ドキュメント を読んでいたら PID の存在チェックやプロセス名監視だけではなく Web サービスの特定の URL にアクセス出来るか否かのチェックも出来るようです。
例えば以下のように monit の設定を行います。
check host localhost with address localhost start program = "/etc/init.d/httpd start" stop program = "/etc/init.d/httpd stop" if failed port 80 protocol http request "/icons/apache_pb2.gif" then exec "/opt/bin/post_to_slack.rb" else if succeeded for 1 cycle then exec "/opt/bin/post_to_slack.rb" group httpd
localhost
の Apache に対してアクセスを行い正常にアクセスが出来なかったら(if failed
)となり exec
でスクリプトが実行され、以下のようなログが記録されます。
[UTC Jan 6 15:27:08] error : 'localhost' failed, cannot open a connection to INET[localhost:80/icons/apache_pb2.gif] via TCP [UTC Jan 6 15:27:08] info : 'localhost' exec: /opt/bin/post_to_slack.rb [UTC Jan 6 15:28:08] info : 'localhost' connection succeeded to INET[localhost:80/icons/apache_pb2.gif] via TCP [UTC Jan 6 15:28:08] info : 'localhost' exec: /opt/bin/post_to_slack.rb
また、Slack にも以下のような通知が発生します。
monit の監視状況は以下のような出力となります。
$ /usr/bin/monit -vI Runtime constants: Control file = /etc/monit.conf Log file = /var/log/monit Pid file = /var/run/monit.pid Debug = True Log = True Use syslog = False Is Daemon = True Use process engine = True Poll time = 60 seconds with start delay 0 seconds Expect buffer = 256 bytes Mail from = (not defined) Mail subject = (not defined) Mail message = (not defined) Start monit httpd = False The service list contains the following entries: Remote Host Name = localhost Group = httpd Monitoring mode = active Start program = '/etc/init.d/httpd start' timeout 30 second(s) Stop program = '/etc/init.d/httpd stop' timeout 30 second(s) Existence = if does not exist 1 times within 1 cycle(s) then restart else if succeeded 1 times within 1 cycle(s) then alert Port = if failed localhost:80/icons/apache_pb2.gif [HTTP via TCP] with timeout 5 seconds 1 times within 1 cycle(s) then exec '/opt/bin/post_to_slack.rb' timeout 0 cycle(s) else if succeeded 1 times within 1 cycle(s) then exec '/opt/bin/post_to_slack.rb' timeout 0 cycle(s) System Name = system_ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal Monitoring mode = active ----------------------------------
おお。
その他にも…
特定のファイルのチェックサムやファイルの中身などをチェックすることが出来るようなので目的に応じて使い分けましょう。
ということで…
メール通知はもう古い!と言うわけではありませんが Chat による運用が選択肢の一つとなった昨今で monit のような従来から利用されているツールで Slack への通知がお手軽に行えるのは嬉しいですね。ただ、メールと同様に頻繁に通知が飛んでしまうとオオカミ少年のようになってしまい通知の意味が無くなってしまいますので通知を飛ばすシチュエーションや通知先は吟味したいですな。
あと monit はプロセスをたたき起こすだけのツールではなくて監視ツールとしての側面もあると思いますので適材適所で使っていければと考えています。
元記事はこちらです。
「monit による障害検知の通知を Slack に飛ばすメモ」