Prometheusで超速監視設定


golang実装でバイナリが配布されているので簡単に設置・動作させられるのがポイントです。
とにかくすぐ動くので（ZabbixとかMuninとかと比べて）簡単に試すことができますよ。
当方はCentOS6で作業しておりますので適宜読み替えてください。

## 簡易動作

### 監視ホスト側

ソースはこちら（https://github.com/prometheus/prometheus） ですがコンパイルが面倒なのでrelease版をダウンロードして実行します。

```
# versionは2018/06/06時点最新 2.2.1
$ wget https://github.com/prometheus/prometheus/releases/download/v2.2.1/prometheus-2.2.1.linux-amd64.tar.gz
$ tar xzf prometheus-2.2.1.linux-amd64.tar.gz
$ cd prometheus-2.2.1.linux-amd64
$ ./prometheus
```
`9090`ポートが解放されていれば`http://yourserver.com:9090`で動作します。
細かい設定は後述。

### クライアント側
exporterを設置する事でホストからのpullの受け口になります。
監視したいサービスに合わせた様々なexporterがあります。[公式によるまとめはこちら](https://prometheus.io/docs/instrumenting/exporters/)
Apache、MySQLはもちろんAWS等のクラウドに対応したexporterも多数用意されているので監視対象に合わせて選んでみるとよいでしょう。

今回は一番ベーシックなCPUやメモリ値を取得するnode_exporterを導入してみます。
nodeと名前にあるのでnodeサーバーの監視用かと思いましたが枝のnodeの事でした。

```
# バージョンと環境に合わせた構成のURLを確認（https://github.com/prometheus/node_exporter/releases）
$ wget https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz
$ tar xzf node_exporter-0.16.0.linux-amd64.tar.gz
$ cd node_exporter-0.16.0.linux-amd64
$ ./node_exporter

# 以下のように実行されました
INFO[0000] Starting node_exporter (version=0.16.0, branch=HEAD, revision=d42bd70f4363dced6b77d8fc311ea57b63387e4f)  source="node_exporter.go:82"
INFO[0000] Build context (go=go1.9.6, user=root@a67a9bc13a69, date=20180515-15:52:42)  source="node_exporter.go:83"
INFO[0000] Enabled collectors:                           source="node_exporter.go:90"
INFO[0000]  - arp                                        source="node_exporter.go:97"
INFO[0000]  - bcache                                     source="node_exporter.go:97"
INFO[0000]  - bonding                                    source="node_exporter.go:97"
INFO[0000]  - conntrack                                  source="node_exporter.go:97"
INFO[0000]  - cpu                                        source="node_exporter.go:97"
INFO[0000]  - diskstats                                  source="node_exporter.go:97"
INFO[0000]  - edac                                       source="node_exporter.go:97"
INFO[0000]  - entropy                                    source="node_exporter.go:97"
INFO[0000]  - filefd                                     source="node_exporter.go:97"
INFO[0000]  - filesystem                                 source="node_exporter.go:97"
INFO[0000]  - hwmon                                      source="node_exporter.go:97"
INFO[0000]  - infiniband                                 source="node_exporter.go:97"
INFO[0000]  - ipvs                                       source="node_exporter.go:97"
INFO[0000]  - loadavg                                    source="node_exporter.go:97"
INFO[0000]  - mdadm                                      source="node_exporter.go:97"
INFO[0000]  - meminfo                                    source="node_exporter.go:97"
INFO[0000]  - netdev                                     source="node_exporter.go:97"
INFO[0000]  - netstat                                    source="node_exporter.go:97"
INFO[0000]  - nfs                                        source="node_exporter.go:97"
INFO[0000]  - nfsd                                       source="node_exporter.go:97"
INFO[0000]  - sockstat                                   source="node_exporter.go:97"
INFO[0000]  - stat                                       source="node_exporter.go:97"
INFO[0000]  - textfile                                   source="node_exporter.go:97"
INFO[0000]  - time                                       source="node_exporter.go:97"
INFO[0000]  - timex                                      source="node_exporter.go:97"
INFO[0000]  - uname                                      source="node_exporter.go:97"
INFO[0000]  - vmstat                                     source="node_exporter.go:97"
INFO[0000]  - wifi                                       source="node_exporter.go:97"
INFO[0000]  - xfs                                        source="node_exporter.go:97"
INFO[0000]  - zfs                                        source="node_exporter.go:97"
INFO[0000] Listening on :9100
```

クライアント側は`9100`ポートを解放します。
`http://yourclient.com:9100/metrics`でメトリクスが表示されればOKです。

次にクライアントをホストの監視対象に入れます。
ホスト側で動いていた`./prometheus`をCtrl+Cでstopして設定ファイルを修正します。

```./prometheus.yaml
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ['localhost:9090']
  # 追記 ここから
  - job_name: 'clientname'
    static_configs:
      - targets: ['yourclient.com:9100']
  # ここまで
```

再度`./prometheus`を実行すると`http://yourserver.com:9090`に反映されます。
ここまででホスト側にクライアントのデータを取得するまでができましたね。

### 異常発生時のアラート設定

ここはホスト側で作業します。
閾値越えでメールを投げるなど、監視としては必要な部分ですね。
Prometheus本体にはこの機構は含まれていないのでAlertmanagerという拡張機能のようなものを別途設置します。
./prometheusとは独立していて別ポートで動作します。

```
$ wget https://github.com/prometheus/alertmanager/releases/download/v0.14.0/alertmanager-0.14.0.linux-amd64.tar.gz
$ tar xzf alertmanager-0.14.0.linux-amd64.tar.gz
$ cd alertmanager-0.14.0.linux-amd64
```

※v0.15.0-rc.1だとエラーで動かなかったので0.14.0を使うことにした。
> level=error ts=2018-06-06T10:29:16.315983112Z caller=main.go:160 msg="Unable to initialize gossip mesh" err="create memberlist: Failed to get final advertise address: No private IP address found, and explicit IP not provided"


AlertManager設定しないと動作しないのでここで一旦アラート設定もろもろを設定します。
Prometheus側には閾値等のアラート発生とするまでの定義条件を、
AlertManager側にはメールで誰々宛に送るよーみたいな設定をそれぞれしていきます。

* prometheusのグローバル設定

``` /path/to/prometheus_dir/prometheus.yml
# もともとコメントしてあった部分を調整します
# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
-      # - alertmanager:9093
+      # AlertManagerに丸投げ Prometheusと同一サーバーで動かす場合はlocalhost:9093
+      - localhost:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
-  # - "first_rules.yml"
-  # - "second_rules.yml"
+  # ルールは別ファイルで定義します
+  "alert_rules.yml"
```

* prometheusのルール設定

``` /path/to/prometheus_dir/alert_rules.yml
# 例：5分間インスタンスダウン
groups:
- name: node_exporter
  rules:
  - alert: InstanceDown
    expr: up == 0
    for: 5m 
    labels:
      severity: critical
    annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} has been down for more than 5 minutes."
```
expr条件の組み立て方は[公式のドキュメント](https://prometheus.io/docs/prometheus/2.0/querying)が詳しい

* alertmanagerの送信設定

```/path/to/alertmanager_dir/alert.yml
global:
  slack_api_url: 'https://hooks.slack.com/services/****'

route:
  receiver: 'test-route'
  group_by: [alertname]
  group_wait:      10s
  group_interval:  5m
  repeat_interval: 1h

receivers:
- name: 'test-route'
  slack_configs:
  - channel: '#channel_name'
```

AlertManagerを起動します！

```
./alertmanager --config.file=alert.yml
```

この設定で監視対象サーバーでポート塞いだりすると5分後にslack飛びました。
簡単で良かった・・・


## しっかり導入するなら

自動起動まわりの設定をしてあげると実運用レベルまで持っていけそうです。
/usr/local/binあたりにシンボリックリンク置いてパスを通します。

```
$ sudo ln -s "/path/to/prometheus" "/usr/local/bin/prometheus"
$ sudo ln -s "/path/to/alertmanager" "/usr/local/bin/alertmanager"
```

起動スクリプトは[このあたり](https://gist.github.com/JoergM/)を参考にさせて頂きました。各々環境に合わせてどうぞ。
自動起動しちゃいましょう。オプションが通らない場合は--help見た方が良いです。

```
$ chmod 755 /etc/rc.d/init.d/prometheus
$ chmod 755 /etc/rc.d/init.d/alertmanager
$ chkconfig --add prometheus
$ chkconfig --add alertmanager
$ chkconfig prometheus on
$ chkconfig alertmanager on
```

クライアント側でも同様にinit.dで動かしてもいいけど、root権限で触ったり仰々しいのでちょっとというサーバーもあるでしょう。
そういった場合は簡易的な死活監視shellをcronで実行してみるというのも手かもしれない。
ちょっと書いてみました。

```
#!/bin/bash
# exporterが動いているか監視します。cronで適当に実行します。

PWD=$(cd $(dirname $0);pwd)
EXPORTERS_DIR="$PWD/exporters/"
PROCESSES=("node_exporter")
for process in ${PROCESSES[@]};
do
  isAlive=`ps -ef | grep "$process" | grep -v grep | grep -v prometheus.sh | wc -l`
  if [ $isAlive = 1 ]; then
    echo $process" is running."
  else
    echo $process" is dead, restarting..."
    # restart
    exporter="${EXPORTERS_DIR}${process}"
    if [ -e $exporter ]; then
      chmod 755 $exporter
      echo "$exporter &"
    else
      echo "$exporter not found"
    fi
  fi
done
```

`crontab -e`でこんな感じに設定すれば毎分動いているか確認して止まっていたら再起動といった感じにお手軽に動くかと（テストしてませんので注意）
`* * * * * path/to/prometheus.sh`




## 考察

やはりバイナリをポンと置いてやれあれが足りないこれが足りない言われずに動くのは気持ちいいですね。
まさにギリシャ神話のプロメテウスが天界から盗み出し人に与えた火の如く、golang世紀の産物だと思いました（ほんとかよ）。
このPrometheusで監視を始めても山に磔にされて肝臓をハゲタカについばまれるような運用対応が必要になる事もないでしょう。
ドキュメントが少ないと言われがちですがそんなに複雑でないのでオフィシャルだけあればいいのではとも思います。
grafanaとの連携で美しいグラフで表示したいというニーズも多数あるようですが
個人的にはアラートがslack・メールに飛んでくるだけで必要十分なので余計な負荷をかけないようスルーします。
が、ちょっと試したいという場合はdockerでささっ見るのがお手頃でした。
`docker run -d -p 3000:3000 grafana/grafana`
grafana詳細はこちら http://docs.grafana.org/installation/

## 参考
[JoergM/alertmanager https://gist.github.com/JoergM/](https://gist.github.com/JoergM/)