AWS上でPrometheus構築(2)

結構時間たっちゃったけど続き
systemd回りとかは[前回](https://qiita.com/holy_road_ss/items/eb0030fd17a2030eb5f0)の記事で書いてるので今回は最初から詳しいことは省きます

## やること
cpu/memの使用率が一定超えたらアラート(node_exporter)
fluentdのプロセス数が想定より低くなってたらアラート
crondが死んだらアラート(普通やらんと思うけど個人的トラウマにより)
通知先はslackのみ

## 監視される側
fluent-plugin-prometheus なるものがあるようですが、今回はそこまでちゃんとチェックしたいわけではないので
`process-exporter`を利用することに。
prometheus的に主流なのは各アプリごとの専用exporterを使うことらしいですが、
まあ一応今回利用するexporterも https://prometheus.io/docs/instrumenting/exporters/ ここに載ってるので良いでしょうきっと

### process-exporterの設置
```bash
cd /opt/prometheus
wget https://github.com/ncabatoff/process-exporter/releases/download/v0.5.0/process-exporter-0.5.0.linux-amd64.tar.gz
tar -zxf process-exporter-0.5.0.linux-amd64.tar.gz
mv process-exporter-0.5.0.linux-amd64/ ./process-exporter
rm -f process-exporter-0.5.0.linux-amd64.tar.gz
```

### process-exorterの設定ファイル
```bash
mkdir -p /opt/prometheus/process-exporter/config/
vi /opt/prometheus/process-exporter/config/process-exporter.yml
```

``` yml:/opt/prometheus/process-exporter/config/process-exporter.yml
process_names:
  - name: "{{.Comm}}"
    comm: 
    - fluentd
  - name: "{{.Comm}}"
    comm:
    - crond
```
https://github.com/ncabatoff/process-exporter
制作元のusageで大体なんとか

基本はcommで用が足りるかと思います。
commでどうもならんようなアプリプロセスの場合にexeを持ち出したり、実行時引数によって同じアプリでも監視対象にしたりしなかったりしたいような場合cmdlineも持ち出す感じかと。
fluentの場合は1起動設定につき引数ascii-8bitあり/なしで2つプロセスが起動するようなので、(例えばmulti-proc利用で親・子で合計3つ起動設定がある場合、6プロセス起動する)
どっちかが監視対象から外れるように書いてあげるとモアベターではありましょうが今回は面倒くさかったので放置

### 起動オプションファイルの作成と設置、反映と起動
このあたりは前回やったことと99%一緒なので省略します


終わったらprometheusサーバにする予定のインスタンスから
`curl http://[[インスタンスIP]]:[[設定したport]]/metrics`
叩いて、なんかすごい量の文字列が返ってきたらok
ラベル `namedprocess_namegroup_num_procs` が割とメインなのでこれで絞っても良いかと思います

## 監視する側
### process-exporter
scrape_configsにprocess-exporter用の設定を突っ込みます。

```
vi /opt/prometheus/prometheusserver/prometheus.yml
```

```yml:/opt/prometheus/prometheusserver/prometheus.yml
#### 途中省略 ####
  - job_name: 'process_test'
    ec2_sd_configs:
      - region: '監視したいインスタンスがいるリージョン'
        port: xxxx # process-exporterのlistenポート
    relabel_configs:
      - source_labels: [__meta_ec2_tag_Service]
        regex: prom_test
        action: keep
      - source_labels: [__meta_ec2_tag_Name]
        target_label: instance

```

### alert managerの設置
```bash
cd /opt/prometheus
wget https://github.com/prometheus/alertmanager/releases/download/v0.16.2/alertmanager-0.16.2.linux-amd64.tar.gz
tar -zxf alertmanager-0.16.2.linux-amd64.tar.gz
mv alertmanager-0.16.2.linux-amd64 alertmanager
rm -f alertmanager-0.16.2.linux-amd64.tar.gz
```

### alert ruleの設定ファイル
前回記事で後回しにした設定部分

```yml:/opt/prometheus/prometheusserver/prometheus.yml
rule_files:
  - /opt/prometheus/prometheusserver/alert_rules.yml
```

```yml:/opt/prometheus/prometheusserver/alert_rules.yml
groups:
  - name: node_exporter # 任意のグループ名
    rules:
      - alert: cpu_exceed # 任意のアラート名
        # 各インスタンスごとの各コアごとCPU idleの使用率を合計してコア数で割ったものが80%を超えていれば
        expr: sum(100 * (1 - rate(node_cpu_seconds_total{job='ec2-test',mode='idle'}[5m]))) by (instance) / count(node_cpu_seconds_total{job='ec2-test',mode='idle'}) by (instance) > 80
        # 80%を超えた状態がこの時間継続すれば。なお省略可能、省略すると即時になるようです。
        # 解除時はここの値は影響しないようです。即座にfiringが解除される模様。
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "cpu of [{{ $labels.instance }}] has been used over 80% for more than 5 minutes."
      - alert: memory_exceed
        expr: 100 * (1 - node_memory_MemFree_bytes{job='ec2-test'} / node_memory_MemTotal_bytes{job='ec2-test'}) > 90
        for: 5m
        labels:
          severity: critical 
        annotations:
          summary: "memory of [{{ $labels.instance }}] has been used over 90% for more than 5 minutes."
  - name: process_exporter
    rules:
      - alert: crond
        expr: namedprocess_namegroup_num_procs{job='process_test',groupname='crond'} < 1
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "[{{ $labels.instance }}] The number of crond process is less than 1 for 1 minutes."
      - alert: fluentd
        expr: namedprocess_namegroup_num_procs{job='process_test',groupname='fluentd'} < 6
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "[{{ $labels.instance }}] The number of fluentd process is less than 6 for 1 minutes."

```
[公式](https://prometheus.io/docs/prometheus/latest/getting_started/)のこの辺から演算子・クエリ周りの情報を追って、あとはprometheusのgraph画面でクエリ投げながらどんな値なのか確認しながらやればそれほど困らないと思います。
node_exporterのrateとかその辺は[ここ](https://prometheus.io/docs/prometheus/latest/querying/functions/#rate)で。
labels/annotationsは[ここ](https://knowledge.sakura.ad.jp/11635/)の説明にもお世話になりました。
(ちなみにprocessのほうでわざわざ1分継続にしてる理由は、即時だとプロセスの再起動でも引っかかってうざそうだから)


### alert managerの設定ファイル
```bash
mkdir -p /opt/prometheus/alertmanager/config/
vi /opt/prometheus/alertmanager/config/alertmanager.yml
```

```bash:/opt/prometheus/alertmanager/config/alertmanager.yml
global:
  slack_api_url: [[slackのwebhook url]]

route:
  receiver: 'slack'
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval:  1m
  repeat_interval: 10m

receivers:
  - name: 'slack'
    slack_configs:
      - channel: '#通知先チャンネル'
        title: '{{ if eq .Status "firing" }}[FIRING]{{else}}[RESOLVED]{{end}} {{ .GroupLabels.alertname }}'
        text: '{{ .CommonAnnotations.summary }}'
        title_link: "http://[[prometheus本体サーバのipなりなんなり]]:[[listen port]]/alerts"
        send_resolved: true
```
slack回りの設定は公式の情報で困らないと思うので特に言うことはないですが、wait/interval回りは後述します
(ソース追ってまで何とかするほど困ることでも無いと思うのと、挙動の謎さに首をかしげ続けるのに疲れたので途中で調査打ち切りましたが)
titleを出し分けしているのは、発生時/回復時でメッセージ本体の左側の帯の色しか変わらないのでせめてもの抵抗

### alert managerの起動設定とか起動
今までと全く同じ流れなので割愛  

あとは試しにcrond止めてみたりすれば確認できるかなと。

### 謎のgroup_interval
自分が意味を勘違いしている可能性は多々あるのですが

```yml
# 通知発生から実際に通知するまで待つ時間
group_wait: 2m
# 2つ目以降の通知が発生し、それが同一グループである場合に通知するまで追加で待つ時間
# alert_rule上で言うとnameは同じだがalertが違う
group_interval:  4m
# 一度通知したアラートの条件が満たされ続けている時、次に通知するまで追加で待つ時間
# alert_rule上で言うとname/alert共に同じ
repeat_interval: 8m
```
大したことではないけど、例えばwaitと各intervalは合計されるのかとか気になったんで上記条件でちょっと試したら

```
08:34 プロセス1 stop
08:34 プロセス2 stop
08:36 プロセス1 アラート通知
08:36 プロセス2 アラート通知
しばらく放置
08:48 プロセス1 アラート通知
08:48 プロセス2 アラート通知
08:54 プロセス1 start
08:54 プロセス2 start
08:56 プロセス1 resolve通知
08:56 プロセス2 resolve通知
```
group_waitとrepeat_intervalは合算されてそうだが…
group_intervalは一体？

```
09:02 プロセス1 stop
09:04 プロセス1 アラート通知
09:04 プロセス2 stop
09:06 プロセス2 アラート通知
09:16 プロセス1 アラート通知リピート
09:18 プロセス2 アラート通知リピート
09:27 プロセス1 start
09:27 プロセス2 start
09:29 プロセス1 resolve通知
09:30 プロセス2 resolve通知
```
group_intervalとは一体？

まあでも、waitとrepeatが直感的に動いてそうなら別に困らないかと思ったので調査終了。
何か知っている方がいればそっと教えてください。