🧨

MySQL、 PostgreSQLのシンプルな死活監視

2022/11/30に公開

はじめに

Amazon RDSなどマネージドなサービスを利用する場合は基本的にCloudWatchなどリソースの状態を監視できるサービスの提供がされている。とても便利。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/MonitoringOverview.html?&tag=querocpedesc-20

が、今回インスタンスに直接DBを乗せる必要があり上記のようなサービスの利用はせず、自前で簡単ではあるが死活監視をしておきたいと思い調べてみた。RDBMSとして広く利用されているMySQL、PostgreSQLについてシンプルなスクリプトを書きたい。ひとまず手元で動くか試してみる。

死活監視の要件としては以下

  • RDBのデーモンが走っていることを確認する
    • 監視結果が違う場合は全て異常と見なす
  • 異常である時Slack・メールなどに通知する
    • SlackのWebhookを使うことにする
  • ローカルから監視する

要件を満たすシェルスクリプトを用意し、cronで定期実行という運用を想定している。

MySQLの監視スクリプト

mysqladmin pingコマンドを実行し、"mysqld is alive"が返ってくる場合のみ正常と見なす。

mysql-alive-monitor.sh
#!/bin/sh
# 標準出力、標準エラー出力しない command > /dev/null 2>&1

IS_ALIVE="mysqld is alive"
RESULT=`mysqladmin --defaults-extra-file=filepath ping 2>&1`

# "mysqld is alive"以外はslackに通知
if [ "$IS_ALIVE" != "$RESULT" ]; then
curl=`cat <<EOS
curl
  -X POST
  https://hooks.slack.com/services/xxx
  -H 'Content-Type: application/json'
  --data '{"text": "<!channel> mysqld is dead"}'
EOS`
eval $curl > /dev/null 2>&1
fi

※シェルスクリプトで直接パスワードを指定すると警告が出てしまうので、設定ファイルを作成し接続オプションでそのファイルを指定する。(コマンド実行履歴には*.shとなるため、historyコマンドなどではパスワードが露呈しないが。)

// 何かしらのエディタで設定ファイルを作成
$ vim ~/.mysql.access.conf

[client]
user = username
password = passwd
host = hostname
port = portnumber

$ chmod 600 .mysql.access.conf
$ mysqladmin --defaults-extra-file=~/.mysql.access.conf ping
mysqld is alive

https://beyondjapan.com/blog/2016/08/mysql56-warning/
https://dev.mysql.com/doc/refman/8.0/ja/mysqladmin.html#option_mysqladmin_defaults-extra-file

シェルスクリプトの実行結果を標準出力したくなかったので、闇に葬った。。。2>&1がミソ
https://unskilled.site/標準出力と標準エラー出力を闇に葬る/

実行結果を出さないだけなら以下。が、標準エラー出力の方は出力される
https://mebee.info/2021/11/25/post-42288/

PostgreSQLの監視スクリプト

PostgreSQLの方もほぼ同じ要領でスクリプトを書いてみる。
PostgreSQL9.3から導入されたpg_isreadyコマンドを使用する。

postgresql-alive-monitor.sh
#!/bin/sh

IS_ALIVE="accepting connections"
RESULT=`pg_isready -h hostname -p portnumber 2>&1`

# "accepting connections"が含まれてない場合、slackに通知
if [ ! `echo "$RESULT" | grep "$IS_ALIVE"` ]; then
curl=`cat <<EOS
curl
  -X POST
  https://hooks.slack.com/services/xxx
  -H 'Content-Type: application/json'
  --data '{"text": "<!channel> postgres is dead"}'
EOS`
eval $curl > /dev/null 2>&1
fi

おわりに

今回はデーモンが動いてるかの確認をして死活監視をした。こだわればキリがなさそうなので、ひとまずこれで異常は検知できるとして当初の要件は満たすことができたとする。
もっとシンプルでいいならping打ってDBサーバーが落ちてないか確認とか、ps | grepでプロセス名で検索するとか。
異常がないか検知するという意味で、SQLを実行するのも良いなと思った。SELECT now();など。
https://gihyo.jp/book/2018/978-4-297-10089-6

一応、GitHubにサンプルを載せておいた。
https://github.com/awonosuke/daemon-monitoring-shellscripts

ほぼ初めてシェルスクリプトを書いた。自分で書くと色々学べるなと再認識。少しづつでも勉強頑張ろう。
今回はRDBのデーモンのみ対応したが、Webサーバーのデーモンなど同じ要領で追加しておこうと思う。(ロードバランサを入れてない構成とかで使えるかも?)

おまけ(shebangについて)

シェルスクリプトの1行目に書く"#!"の部分をシバン、シェバンと呼び、これから使用するインタプリタを指定する役目がある。当初これを#!/bin/shとしていたが、死活監視とは別件でシェルスクリプトを書くことになり色々調べていたらある記事で#!/usr/bin/env bashというような書き方をしており、「なんだこの書き方は?」となり調べてみることにした。

例に示した書き方はenvコマンドを利用してPATHに定義されているパスの中から定義順にbashが見つかれば、最初にbashの存在するパスが適用されるという感じらしい、なるほど。また、bashがデフォルトシェルの環境で#!/bin/shを指定するとPOSIX(Wikipedia)機能とやらが有効になり、できるだけshっぽく振る舞ってくれるらしい。つまり、bashで動く前提で書いてるスクリプトが期待通りの挙動をしないことがある。プログラム特有の機能を使う際は指定するのが良い。

対象インタプリタの絶対パスを知っているなら/bin/bashといった指定で問題はない。その代わり、存在しない場合エラーが起きる。そのため、#!/usr/bin/env bashとすることでヒットさせやすくするという具合のようだ。

shebangについては以下リンクを参考にしました。
https://sechiro.hatenablog.com/entry/20120806/1344267619
https://stackoverflow.com/questions/16365130/what-is-the-difference-between-usr-bin-env-bash-and-usr-bin-bash
https://moneyforward.com/engineers_blog/2015/05/21/bash-script-tips/
https://rcmdnk.com/blog/2016/09/20/computer-linux-bash/

参考URL

MySQL

https://dev.mysql.com/doc/refman/8.0/ja/mysqladmin.html
https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0012
https://cat-marketing.jp/2021/08/12/1309/

PostgreSQL

https://www.postgresql.jp/document/9.3/html/app-pg-isready.html
https://mebee.info/2020/12/29/post-25311/
https://www.slideshare.net/naka24nori/postgre-sql-55593111
https://www.ospn.jp/osc2015-do/pdf/OSC2015_do_tis.pdf
https://www.fujitsu.com/jp/products/software/resources/feature-stories/postgres/article-index/monitoring/

シェルスクリプトもろもろ

http://www.ajisaba.net/sh/var_command.html
http://unix.oskp.net/shellscript/here_document.html
https://qiita.com/ysk_n/items/58493af94d41dff348d6
https://www.1ft-seabass.jp/memo/2022/04/29/shell-discord-send-message-eval-command/
https://www.web-dev-qa-db-ja.com/ja/bash/if-からの-:too-many-argumentsエラーの意味(角括弧)/1070004748/
https://shellscript.sunone.me/input_output.html
https://gist.github.com/mori-dev/613034

Discussion