kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Mackerel と diff-detector を組み合わせてファイルの変更検知を実現する

背景

去年,モニタリングサービスを Zabbix から Mackerel に移行したときに,ファイルの変更検知(例えば /etc/passwd など)を Mackerel でうまく実現できなくて,諦めてしまっていた経緯があった.もしかしたら公式機能であるのかも...?

Zabbix だと

Zabbix から公式に提供されている「Template OS Linux」の中に /etc/passwd の変更検知をする設定がある.ちなみに,今回は Zabbix 2系を前提にしている.

  • アイテム
    • 名前 : Checksum of /etc/passwd
    • キー : vfs.file.cksum[/etc/passwd]
  • トリガー
    • 名前 : /etc/passwd has been changed on {HOST.NAME}
    • 条件式 : {Template OS Linux:vfs.file.cksum[/etc/passwd].diff(0)}>0

仕組みをザックリと説明すると,Zabbix で vfs.file.cksum を使うとファイルのチェックサム(例えば 1938292000 のような数値)を取得できるため,その値をメトリクスとして保持している.さらに Zabbix のトリガー条件式では .diff という「前回のメトリクスと違った場合」を検知する関数があるので,チェックサムが変更された場合にアラートを鳴らすことができる.逆に言うと「変更されたことを検知できる」だけであって「どのように変更されたか?は検知できない」ことに注意する.

メルカリの事例

最近開催されていた Mackerel DAY の資料を見ていたら,メルカリでは diff-detector という独自ツールを使って /etc/passwd の変更検知を Mackerel で実現しているとのことで,さっそく試してみようと思った.diff-detector 以外でも,メルカリの Mackerel 活用事例が圧倒的で非常に勉強になった!スゴすぎ...!

diff-detector を読んだ

まずは diff-detector 単体の機能を把握するために,実装を読んでみた.Go と Perl 版があるけど,今回は Go を選んだ.実装としては,少し書き捨てっぽい印象も受けたけど(go fmtgoimports を流すと結構変更点が出た...w),必要十分な機能は揃っていた.

github.com

  • 特徴
    • ファイルの変更検知ではなく「標準出力の変更検知」ができる
    • 「標準出力の変更検知」ができるので,検知の対象としてコマンドを指定する(例えば cat /etc/hosts など)
    • 一次ディレクトリに新旧の標準出力を含めたファイルを保持しているため「どのように変更されたか?」の具体的な変更点も確認できる
    • 初回実行と変更なしの場合は 0 が返り,変更ありの場合は 1 が返る
  • 実装
    • コマンドオプションの終点を意味する -- をパースするために flags.NewParser(opts, flags.PassDoubleDash) を使っている
    • 標準出力(旧)は os.TempDir() で取得している
      • /tmp/500-diff-detector-c9f995bb55ec9fc62e0ca720b3ebfbad のような絶対パスになる
    • 標準出力(新)は ioutil.TempFile() で取得している
      • /tmp/temp766915122 のような絶対パスになる
    • 一次ディレクトリに保持するファイル名に使うハッシュにソルト値を含めたい場合は --identifier オプションが使える
    • 変更検知は diff -U 1 を使っている
      • -U-u と同じで,差分の前後の行数を指定することができる

具体的には以下のように実行する.

# 初回実行
$ diff-detector -- cat /etc/passwd
Notice: first time execution command: 'cat /etc/passwd'

# 変更なし
$ diff-detector -- cat /etc/passwd
OK: no difference: ```root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:...```

# 変更あり
$ diff-detector -- cat /etc/passwd
NG: detect difference: ```@@ -31 +31,2 @@
 jenkins:x:502:502::/home/jenkins:/bin/bash
+kakakakakku:x:503:503::/home/kakakakakku:/bin/bash```

Mackerel と diff-detector を組み合わせる

ここからやっと本題で,Mackerel と diff-detector を組み合わせる.基本的には diff-detector をチェックプラグインとして使えるようにするだけで良かった.オプションなどは公式ドキュメントを見てカスタマイズすると良さそう(例えば /etc/passwd のインターバルをもう少し長くするなど).

mackerel.io

設定は簡単で /etc/mackerel-agent/mackerel-agent.conf に以下を追加した.

[plugin.checks.diff_etc_passwd]
command = "/usr/local/bin/diff-detector -- cat /etc/passwd"

この状態で変更検知を起こすと,以下のようにアラートが Slack に通知された.Zabbix のときには実現できていなかった「変更点」も確認できるので,非常に便利だった.

f:id:kakku22:20171019183454p:plain

関連する公式チェックプラグイン

id:Soudai さんに教えて頂いたファイル関連の公式チェックプラグインも紹介しておこうと思う.今回の変更検知の要件には合わなかったが,知っておくといざ必要になったときに良さそう.

まとめ

  • Mackerel でファイルの変更検知を実現するために diff-detector を試してみた
  • 「変更されたこと」だけではなく「どのように変更されたか?」も検知できるので,非常に便利だった
  • diff-detector のような汎用的なチェックプラグインが Mackerel 公式であっても良さそう 🙏
  • Mackerel の監視設定は現在「閾値」しか設定できないので,Zabbix の .diff のような「前回のメトリクスと違った場合」を設定できると,監視設定の幅が広がりそう 🙏

関連記事

メルカリの Mackerel 活用事例を詳細に解説されている.すごく参考になった!

blog.a-know.me