オヤジが初めてMackerelを利用してみた

はじめに

ショボイ記事となってしまいましたが、どうかご勘弁をば。
なんかリンク表示もダサいし。

自己紹介

アプリ、管理畑で20年ほどITの業界いたのですが、ひょうんな事からインフラエンジニアも兼任することになります。
それが1年ほど前のこと。
そんなほぼ50のオヤジ:older_man:です。

Mackerelとの出会い

他社の監視サービスを利用していたが、正直主観であまりイケていない監視サービスだったので代替先の検討を開始する。
まぁ:moneybag:の問題もあるにはあった…
そんな梅雨も明けた頃にMackerelに出会う。

株式会社はてなは昔から知っていて、技術集団のイメージがあり、初期の頃からはてな関連のサービスを利用していたこともあって、この会社のサービスであればと評価を開始!
少数サーバに対して評価し始めたところ、すこぶる良い!しかもイケている!:smile:と確信。
しかも安価である。これはと社内導入を決めた。
その後Mackerel Dayに参加し、:beer:を大量にゲットした!

サーバ構成例

さて、いよいよMackerel導入なのだが、通常はLBがあって、WEBサーバがあって、DBサーバがあってというようにサーバの役割がおおまかに決まっていることが多いかなと思います。
1台のサーバでWEB・DBサーバを兼務する場合もあるが、1台構成での運用は「サーバ停止=サービス停止」となるため、2台のサーバで運用し、縮退してでもサービス継続をしたいですよね。
(これらはDRBD、pacemaker、heartbeatなどを利用しても実現可能)

次章は、サーバを2台用意して、サーバ1をWEBサーバ、サーバ2をDBサーバとして運用し、サーバ1,2のいずれかが停止した場合は自動的に縮退し、障害復旧まで一時的に1台のサーバでWEB・DBサーバを兼務するというサーバ構成を例として話を進めます。

上記サーバ構成時のMackerel適用時のプチ課題?

Mackerelではサービスとロールという主に2つの設定が可能です。

下記リンクにそれぞれの意味が記載されています。

サービス、ロールを作成する - Mackerel ヘルプ

簡易な説明
サービス 1つのサービスを提供するサーバ群
ロール サービスに紐付いたサーバ群の中で役割

具体例として、WEBサービスを複数展開していて、それぞれ動画配信サイト、記事配信サイトとします。
サービスについては下記のようなイメージとなります。

WEBサービス サービス名
動画配信サイト Mackerel上でのサービス名:douga
記事配信サイト Mackerel上でのサービス名:kiji

ロールについては、動画配信・記事配信サイトともに複数のサーバで構成されているとすると、下記のようなイメージとなります。

サービス名 サーバ名  ロール名
Mackerel上でのサービス名:douga サーバ1 WEBサーバ
サーバ2 DBサーバ
Mackerel上でのサービス名:kiji サーバ11 WEBサーバ
サーバ12 WEBサーバ
サーバ13 DBサーバ
サーバ14 DBサーバ

※別々のサービスのWEBサービスが同じロール名で良いかは判断が必要で自分は分けています。

さて、「サーバ構成」部分で書いた「サーバを2台用意して、サーバ1をWEBサーバ、サーバ2をDBサーバとして運用し、サーバ1,2のいずれかが停止した場合は自動的に縮退というサーバ構成」の場合、1サーバが複数のサービス、ロールを担うことなります。。

例のようなサーバ構成では、妥協案としては各サーバごとにサーバを特定可能できるサービス名・ロール名をつけるなど工夫が必要かもしれないです。
もしくはロール名にどっかの雑誌のようにWEB+DBと付けちゃうとか。
この辺りは正直うまい整理を見いだせていないですね…

実際に監視開始

URL外形監視やディスク容量監視やCPUの監視などは基本備わっています。
その他はオプションでMackerelプラグインと自作のスクリプトを併用しています。

昨日の@sugaiさんも利用されてますが式による監視も導入しています。
こちらはディスク容量の枯渇が後どれくらいかに利用しています。

Mackerelには豊富なプラグインがある。詳細は下記リンクより。
Mackerel Agentプラグイン
とても大変助かる~!

監視している項目の差し支えない範囲内の一部をご紹介します。(実際は複数のconfファイルですがまとめています)

/etc/mackerel-agent.conf
include = "/etc/mackerel-agent/conf.d/*.conf"

[host_status]
on_start = "working"
on_stop  = "poweroff"

[plugin.metrics.linux]
command = "mackerel-plugin-linux"

[plugin.metrics.multicore]
command="mackerel-plugin-multicore"

[plugin.metrics.inode]
command="mackerel-plugin-inode"

[plugin.metrics.uptime]
command = "mackerel-plugin-uptime"

# ログファイル内のアラート検知(Mackerel自体のエラーログなども監視)
[plugin.checks.ログファイル監視]
command = "check-log --file /xx/yy/zz/*.log --exclude 'key1|key2' --pattern ERROR --return"

# 常駐プロセスのチェック
[plugin.checks.check_プロセス名]
command = "check-procs --pattern プロセス名"
action = { command = "bash -c '[ \"$MACKEREL_STATUS\" == \"CRITICAL\" ]' && service プロセス名 start", user = "root" }

# ミドルウェアのプロセスチェック
[plugin.checks.ミドルチェック]
command = '(ip a | fgrep -q aaa.bbb.ccc.ddd; exit $(( $? ^ 1 )) ) || check-procs --pattern ミドルウェア名'

# DBに実際に接続できるかのチェック(DBが起動しているだけではダメなので。xxx.shで導通のチェックをしている)
[plugin.checks.DB接続チェック]
command = '(ip a | fgrep -q aaa.bbb.ccc.ddd; exit $(( $? ^ 1 )) ) || xxx.sh'

# ポートが開いているか等のチェック
[plugin.checks.portチェック]
command = "xxx.sh"
max_check_attempts = 2

# OSやミドルやアプリのバージョン情報をメタデータに登録しています
[plugin.metadata.各種バージョン情報]
command = "python XXX.py"
execution_interval = 10

# 簡易なDBのロックチェック
[plugin.metrics.DBロックチェック]
command="xxx.py"
type="metric"

※バージョンチェックは@a-know さんにバージョン情報とかってどうやればできます質問をした結果をふまえて。
@a-knowさん、いつもありがとうございます!
※DRBD、pacemaker、heartbeat関連のプロセス監視や自作スクリプトなどは省略
※fgrep辺りについては下記リンクに記載しています(宣伝…)
pacemaker+heartbeat環境においてVIPの役割ごとに対するMackerelの監視
※Apache2については諸条件より適用していない。

その他もろもろあり、Windows Update監視なども自作していますが、ご覧の通り煩雑ではあります…

どうしてもあれもこれもと盛り込みたくなるのだが、考え方をシフトしました。
1. 障害検知のための指標
2. サーバ状態収集のための指標
双方は異なる観点であるため、まずはひとつめの「障害検知のための指標」から導入を開始しました。
最近ようやく「サーバ状態収集」の方に着手できてきたかな。

この辺りは下記の情報を参照してブラッシュアップを実施しています。

1. Mackerelブログ
2. soudai1025 さんのMackerel プラグインアドベントカレンダー(全部CRE) Advent Calendar 2017

障害時の通知について

Mackerelは障害検知時に複数の通知先を設定可能です。
これがホント助かる!:smile:
オヤジは夜中は寝たいもの。

詳細は下記リンク。
監視・通知を設定する

例えばこのような通知も簡易にできます。
1. Mackrelで障害検知し、Slackとメール通知。
2. 重量な障害は上記に加えてTwilioなどで着電通知。
3. さらに監視にはルールの設定もできるため、深夜帯は対応必須の障害のみ電話をかける通知。
なども用意に設定可能です。

またAPIも用意されています。
Mackerel API ドキュメント(v0)

よく利用しているAPI

API名 URL
通知チャンネルの一覧取得 https://mackerel.io/api/v0/channels
通知グループの一覧取得 https://mackerel.io/api/v0/notification-groups
ホスト情報の取得 https://mackerel.io/api/v0/hosts/

通知チャンネルの一覧取得、通知グループの一覧取得については、現状通知グループ内の通知チャンネルを手動で変更することがあり、通知を外したままだと通知されないため、スクリプトで状態を取得して、Slackに通知しています。

下記のようなイメージ。

xxx.sh
#!/bin/sh

変数A=`curl -s https://mackerel.io/api/v0/channels -H "X-Api-Key:<APIキー>" -H "Content-Type: application/json" -X GET | jq '.channels[] | select(.name=="参照したい通知チャンネル名").id'`

変数B=`curl -s https://mackerel.io/api/v0/notification-groups -H "X-Api-Key:<APIキー>" -H "Content-Type: application/json" -X GET | jq '.notificationGroups[] | select(.name=="通知チャンネルが含まれて欲しい通知グループ名").childChannelIds' | grep $変数A

if [ "${変数B}" = "" ]; then
        MESSAGE="◯◯通知グループに△△通知チャンネルが設定されていません"
else
        MESSAGE="通知設定OK"
fi

WEBHOOKURL="https://hooks.slack.com/services/xxxxxxx/yyyyyy/zzzzzz" # 取得したWebHookURL
CHANNEL=${CHANNEL:-"#チャンネル名"}
USERNAME=${BOTNAME:-"名前"}
FACEICON=${FACEICON:-":ghost:"}
MESSAGE=${MESSAGE:-""}

curl -s -S -X POST --data-urlencode "payload={\"channel\": \"${CHANNEL}\", \"username\": \"${USERNAME}\", \"icon_emoji\": \"${FACEICON}\", \"text\": \"${MESSAGE}\" }" ${WEBHOOKURL} > /dev/null

みたいな感じです。もっと良い方法はありますよね…
通知チャンネル、通知グループとアカウントを紐付けられたらもっと良いかも。

おまけ 最近知った便利機能

ダッシュボードを作成した際に「グラフを共有」からiframeなどをひっぱってきた以来ほとんど「グラフを共有」使っていなかったのですが、右上にグラフの画像をpng形式でダウンロードするためのボタンを見つけました!(笑)
この機能2年以上も前に提供されていたんですね。

グラフ画像がダウンロードできるようになりました

Slackなど利用していない人に送るのに非常に便利。
※ここだけの話、画面キャプチャしてました(笑)

まとめ

新米インフラエンジニアのオヤジですが、どうにか少しは形になってきたかなと思っています。
試行錯誤の連続の段階ですが、今後は収集したサーバの状態から通常運用時に事前かつ適切に対応可能となるようなKnowHowを積み重ねていければと思っています。

最近のMackerelはアラートの状態(WARNやCRITICAL)に応じて、コマンドを発行できるようになったりと毎週毎週便利な機能が提供されています。
今後も機会があれば記事を書けたらなと思います。

結論:オヤジでも十分使える・使いやすいということです:exclamation:
でも、まだまだです…:older_man:ガンバレっ

明日は @papix さんの記事です!

PS はてなの中の方々日々ありがとうございます。