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

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

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

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

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

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

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

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

## 上記サーバ構成時のMackerel適用時のプチ課題？
Mackerelではサービスとロールという主に２つの設定が可能です。

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

[サービス、ロールを作成する \- Mackerel ヘルプ](https://mackerel.io/ja/docs/entry/howto/create-services-and-roles)


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

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

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

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

| サービス名 | サーバ名 |　ロール名 |
|:-----------|:------------|:------------|
| Mackerel上でのサービス名：douga       | サーバ１        |WEBサーバ|
|        | サーバ２        |DBサーバ|
| Mackerel上でのサービス名：kiji      | サーバ１１      |WEBサーバ
|        | サーバ１２        |WEBサーバ|
|        | サーバ１３        |DBサーバ|
|        | サーバ１４        |DBサーバ|

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

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

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

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

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

Mackerelには豊富なプラグインがある。詳細は下記リンクより。
[Mackerel Agentプラグイン](https://github.com/mackerelio/mackerel-agent-plugins)
とても大変助かる~！

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

```sh:/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](https://qiita.com/a-know) さんにバージョン情報とかってどうやればできます質問をした結果をふまえて。
@a-knowさん、いつもありがとうございます！
※DRBD、pacemaker、heartbeat関連のプロセス監視や自作スクリプトなどは省略
※fgrep辺りについては下記リンクに記載しています（宣伝…）
[pacemaker+heartbeat環境においてVIPの役割ごとに対するMackerelの監視](https://qiita.com/vanityangel/items/2a9c0092bd9aef56f8eb)
※Apache2については諸条件より適用していない。

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

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

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

**1.** [Mackerelブログ](https://mackerel.io/ja/blog/)
**2.** [soudai1025](https://qiita.com/soudai1025) さんの[Mackerel プラグインアドベントカレンダー(全部CRE） Advent Calendar 2017](https://qiita.com/advent-calendar/2017/mackerel-plugins)

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

詳細は下記リンク。
[監視・通知を設定する](https://mackerel.io/ja/docs/entry/howto/alerts)

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

またAPIも用意されています。
[Mackerel API ドキュメント（v0）](https://mackerel.io/ja/api-docs/)

よく利用しているAPI

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

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

下記のようなイメージ。

```sh: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形式でダウンロードするためのボタンを見つけました！（笑）
この機能２年以上も前に提供されていたんですね。

[グラフ画像がダウンロードできるようになりました](https://mackerel.io/ja/blog/entry/2015/06/26/110226)

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

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

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

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

明日は [@papix](https://qiita.com/papix) さんの記事です！

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