prometheus で雑に始めるサーバ監視

# 概要

prometheus をつかって個人サーバを監視するのを雑に始める。


# 使用するもの

* [prometheus](https://prometheus.io/)
* [docker](https://www.docker.com/)

prometheus はデータを pull 型で収集するアプリケーションで、メトリクス取得のために exporter とアプリケーションをそれぞれ必要に応じて利用する必要がある。prometheus および expoter は自前でインストールするといろいろ面倒なので docker のコンテナを使って構築する。ここでは grafana は扱っていない。

今回自分が構築した環境は下記のとおり。

* Ubuntu 16.04.1 LTS
* Docker 1.13.0
* prometheus 1.5.0

# 内容

最初にここでやる全部の作業としてまとめを記載して、あとでそれぞれ詳細を書く。

## まとめ

* ここでは下記メトリクスが取得できるようにする
  * CPU やメモリなどの基本的な項目
  * docker コンテナそれぞれの基本的な項目
* docker のコンテナで構成する
  * docker の User-defined network を使う
     * 直接外から見られないようにするため
     * コンテナの IP アドレスを固定するため
* prometheus および alertmanger の UI 用にリバースプロキシする
* アラート飛ばせるようにする
  * 設定例は gmail

当たり前だけど１台なので自身が落ちてたらどうしようもない。

### 構成

![d60de4f270285bc85a846ab084fb3a2f.png](https://qiita-image-store.s3.amazonaws.com/0/6975/8e9044bf-87d3-b4f4-51ab-2e7486fda0a9.png)


コンテナ情報
IP アドレスは範囲内ならなんでもいいので下記のは例。

| コンテナ名                   | IPアドレス  | ポート|
|-----------------------------|------------|------|
| prometheus-container        | 172.18.0.2 | 9090 |
| node-exporter-container     | 172.18.0.3 | 9100 |
| alertmanager-container      | 172.18.0.4 | 9093 |
| cadviser-container          | 172.18.0.6 | 8080 |


### 手順

Docker の userdefined network 作成

```console
$ docker network create --subnet=172.18.0.0/24 prometheus_nw
```

イメージの取得

```
$ echo "prom/prometheus prom/alertmanager google/cadvisor prom/node-exporter" | xargs -n 1 docker pull
```

prometheus および exporter でそれぞれ必要な設定ファイルを設置。ここでは /home/prometheus 以下とする。変更する場合は後述する 起動時の引き数も変更する。

```
$ pwd
/home/prometheus
$ tree -L 2
.
├── alertmanager
│   ├── alertmanager.yml
│   └── data
└── prometheus
    ├── alerts.rule
    ├── data
    └── prometheus.yml
                                                                                                                                           4 directories, 3 files                                                                                                                                                                                                                                                             
```


```yaml:prometheus.yml
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

rule_files:
  - alerts.rule

scrape_configs:
- job_name: node
  static_configs:
  - targets: ['172.18.0.3:9100']
- job_name: docker
  static_configs:
  - targets: ['172.18.0.6:8080']
```

```alerts.rule
ALERT InstanceDown
  IF up == 0
  FOR 5m
  LABELS { severity = "page" }
  ANNOTATIONS {
    summary = "Instance {{ $labels.instance }} down",
    description = "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
  }
```

アラート飛ばす先の設定。
下記は Gmail で送る場合の例。

> Sending email with the Alertmanager via Gmail 
https://www.robustperception.io/sending-email-with-the-alertmanager-via-gmail/

アプリ毎にパスワード設定する場合のヘルプ

> Sign in using App Passwords
https://support.google.com/accounts/answer/185833?hl=en

パスワードはここでつくる
https://security.google.com/settings/security/apppasswords

```yaml:alertmanager.yml
route:
  receiver: hogehoge-mail
receivers:
  - name: hogehoge-mail
    email_configs:
    - to: "hogehoge@example.com"
      from: "hogehoge@example.com"
      smarthost: smtp.gmail.com:587
      auth_username: "hogehoge@example.com"
      auth_identity: "hogehoge@example.com"
      auth_password: "brabrabrabra"
```

起動

```console
$ docker run --name=prometheus-container -d --net=prometheus_nw --ip=172.18.0.2 -v /home/prometheus/prometheus:/prometheus prom/prometheus -config.file=/prometheus/prometheus.yml   -alertmanager.url=http://172.18.0.4
$ docker run --name=node-exporter-container -d --net=prometheus_nw --ip=172.18.0.3 -v "/proc:/host/proc"  -v /sys:/host/sys -v /:/rootfs prom/node-exporter -collector.procfs /host/proc -collector.sysfs /host/sys -collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)"
$ docker run --name=alertmanager-container -d --net=prometheus_nw --ip=172.18.0.4 -v /home/prometheus/alertmanager:/alertmanager prom/alertmanager -config.file=/alertmanager/alertmanager.yml -web.external-url=http://alertmanager.example.com
$ docker run --name=cadvisor-container -d --net=prometheus_nw --ip=172.18.0.6 --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --detach=true  google/cadvisor:latest
```

nginx 設定して UI を見られるように

```nginx:
upstream prometheus {
  server 172.18.0.2:9090;
}
upstream alertmanager {
  server 172.18.0.4:9093;
}

server {
  listen 80
  server_name prometheus.example.com;
  
  location / {
    proxy_pass http://prometheus;

    auth_basic "Prometheus";
    auth_basic_user_file ".htpasswd";
  }
}
server {
  listen 80
  server_name alertmanager.example.com;
  
  location / {
    proxy_pass http://alertmanager;

    auth_basic "AlertManager";
    auth_basic_user_file ".htpasswd";
  }
}

```

htpasswd 作る

```
$ cd /etc/nginx/
$ sudo htpasswd -c .htpasswd prometheus
```
nginx を reload するなり restart するなりして prometheus.example.com および alertmanager.example.com が表示できることを確認。

以上、あとは自分の環境用に設定を変更したり必要なものをインストールしたり、 grafana を使ってダッシュボードを作ったりする。

## 雑記

### prometheus について

サーバ監視するにはいろいろあるようだけど、最近は prometheus というのがホットらしい。
prometheus は それ自身と exporter で構成される

> exporter の一覧
https://prometheus.io/docs/instrumenting/exporters/

prometheus を動かすには apt などのパッケージ管理システムを使ってインストールすることも出来るけど、わりと古かったりするのが面倒なので公式で提供されている docker イメージを使うことにする。

ちなみに 一旦 apt で入る prometheus は最新のものと設定ファイルなどが異なる可能性があるので 既存のものから docker イメージの prometheus に移行する際は注意が必要。


### prometheus on docker

> prometheus 公式の docker イメージ
https://hub.docker.com/u/prom/

とりあえず prometheus だけ起動する場合

> Using Docker
https://prometheus.io/docs/introduction/install/#using-docker

ここのようにホスト側のポート使ってもいいけど、expoter 系が外部から直接見られるのって怖いなーという感じ。 iptables などで設定しても良いんだろうけど、今回は docker のユーザ定義ネットワークを使っている。

https://docs.docker.com/engine/userguide/networking/

また、適当にネットワークにアタッチする場合 IP アドレスが起動するたびに変わってしまう。prometheus の設定に直書きだと思うので個々らへんは固定でやる。 ここらへんはコンテナ起動時に設定する。起動したままネットワークにアタッチする場合は固定にできなかった気がする。

http://qiita.com/paihu/items/17aa47906dd2bf935a25
http://qiita.com/takara@github/items/2349fff473474d7fcf47

下記のようなコマンドで監視系のコンテナをぶら下げるネットワークを作ることができる。たぶんこれだけ。このネットワークを指定してコンテナを作ったり起動途中でアタッチしたりするとこのネットワークに入る。指定せずに起動した場合はデフォルトのネットワークの方に入る。

```
$ docker network create --subnet=172.18.0.0/24 prometheus_nw
```

#### docker コンテナについて

ざっくり docker pull すると下記のようになる。（横着して xargs で書いてる）

```
$ echo "prom/prometheus prom/alertmanager google/cadvisor prom/blackbox_exporter prom/node-exporter" | xargs -n 1 docker pull
```
説明

| 名前                  | 雑な説明  | リポジトリ |
|-----------------------------|------------|---| 
| prometheus | メトリクスを exporter から pull してファイルシステムに保存する | https://github.com/prometheus/prometheus |
| node-expoter | CPU とか メモリ とか見られるからとりあえずいれとけって exporter |  https://github.com/prometheus/node_exporter | 
| alertmanager | アラート飛ばすときにどこに飛ばすかとか静観するかとか設定できる。ルール自体は prometheus で指定するけど。 | https://github.com/prometheus/alertmanager | 
| cadvisor | Docker コンテナの監視に使うらしい。 mysql-exporter と同じポートを使うのでホストに紐付ける場合は注意。 | https://github.com/google/cadvisor |

今回は下記のように設定する。 container を suffix にしてるのはコマンドなどと混同しないようにするため。

#### 起動コマンド

prometheus

```console
$ docker run --name=prometheus-container --net=prometheus_nw --ip=172.18.0.2 -d -v /home/prometheus/prometheus:/prometheus prom/prometheus -config.file=/prometheus/prometheus.yml   -alertmanager.url=http://172.18.0.4
```

node_exporter

```console
$ docker run --name node-exporter-container -d --net=prometheus_nw --ip=172.18.0.3 -v "/proc:/host/proc"  -v "/sys:/host/sys" -v "/:/rootfs" prom/node-exporter -collector.procfs /host/proc -collector.sysfs /host/sys -collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)"
```

参考 https://github.com/prometheus/node_exporter
今回の場合、 docker を動かしてるので README の最後にあるように起動する。

alertmanager

UI の URL は自分の環境に合わせて。

```console
$ docker run --name alertmanager-container -d --net=prometheus_nw --ip=172.18.0.4 -v /home/prometheus/alertmanager:/alertmanager prom/alertmanager -config.file=/alertmanager/alertmanager.yml -web.external-url=http://alertmanager.example.com
```

cadvisor

```console
$ docker run --name=cadvisor-container --net=prometheus_nw --ip=172.18.0.6 --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --detach=true  google/cadvisor:latest
```


### configuration for prometheus

設定ファイルなどはホスト側に置くことになる。置く場所は好きな場所でよい。自分の場合はもともと apt で入った prometheus ユーザで動かしていたので とりあえず /home 以下に prometheus 設定を入れた。

```console
$ pwd
/home/prometheus
$ tree -L 2
.
├── alertmanager
│   ├── alertmanager.yml
│   └── data
└── prometheus
    ├── alerts.rule
    ├── data
    └── prometheus.yml
                                                                                                                                           4 directories, 3 files                                                                                                                                                                                                                                                             
```

prometheus 自体の設定

参考URL

> https://prometheus.io/docs/operating/configuration/
https://prometheus.io/docs/introduction/getting_started/

下記のものはとりあえず node_exporter と docker のものを pull するようにする設定。exporter を増やしたりした場合は適宜変更するファイル。

```yaml:prometheus.yml
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

rule_files:
  - alerts.rule

scrape_configs:
- job_name: node
  static_configs:
  - targets: ['172.18.0.3:9100']
- job_name: docker
  static_configs:
  - targets: ['172.18.0.6:8080']
```

アラートルールは別ファイルに書く。

参考URL
> https://prometheus.io/docs/alerting/rules/

とりあえず node_expoter が落ちてたらアラート飛ばす例。アラートルールの知見ほしいですね。

```alerts.rule
ALERT InstanceDown
  IF up == 0
  FOR 5m
  LABELS { severity = "page" }
  ANNOTATIONS {
    summary = "Instance {{ $labels.instance }} down",
    description = "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
  }
```

alertmanager 側の設定

ここではアラート飛ばす先の設定をする。

下記は Gmail で送る場合の例。

> Sending email with the Alertmanager via Gmail 
https://www.robustperception.io/sending-email-with-the-alertmanager-via-gmail/

アプリ毎にパスワード設定する場合のヘルプ

> Sign in using App Passwords
https://support.google.com/accounts/answer/185833?hl=en

パスワードはここでつくる
https://security.google.com/settings/security/apppasswords

その他いろいろ対応しているので必要な通知先を設定する。prometheus で付与した job やラベルによって通知先や通知メッセージを変えたりできるのでうまいことやる。

```yaml:alertmanager.yml
route:
  receiver: hogehoge-mail
receivers:
  - name: hogehoge-mail
    email_configs:
    - to: "hogehoge@example.com"
      from: "hogehoge@example.com"
      smarthost: smtp.gmail.com:587
      auth_username: "hogehoge@example.com"
      auth_identity: "hogehoge@example.com"
      auth_password: "brabrabrabra"
```

#### 設定反映について

docker で起動した prometheus や exporter の設定を変更した場合、 docker stop && docker start でよい。

または systemd が使える場合は事項のように設定して systemctl restart で行っても良さそう。

#### 起動の管理およびアップデート

Ubuntu 16.04.1 では systemd 使ってるのでこれで起動管理できたら楽そう

> Start containers automatically
https://docs.docker.com/engine/admin/host_integration/

下記の様に設定する。run のものは -d または --detach=true を削除する必要がある。
>  Make sure you don’t use “-d” for “detached mode”. The command run from “ExecStart” needs to run in the foreground.

```/etc/systemd/system/prometheus-container.service
[Unit]
Description=prometheus container
Requires=docker.service
After=docker.service
                                                                                                                                                                  [Service]
Restart=always
ExecStart=
ExecStart=/usr/bin/docker run --name=prometheus-container --net=prometheus_nw --ip=172.18.0.2 -v /home/prometheus/prometheus:/prometheus prom/prometheus -config.file=/prometheus/prometheus.yml -alertmanager.url=http://172.18.0.4
ExecStop=/usr/bin/docker stop -t 2 prometheus-container
ExecStopPost=/usr/bin/docker rm -f prometheus-container

[Install]
WantedBy=default.target
```

このようにしておけば、 アプリケーションのアップデートは下記のようにするだけでよい。

```
$ docker pull prom/prometheus 
$ sudo systemctl restart prometheus-container.service
```

下記記事のように ExecStartPre で pull しても良いかもしれないが、 restart するだけでアップデートされるのは個人的に好みではないのでやってない。

> dockerコンテナをsystemdで管理させる
http://qiita.com/74th/items/e8dc1ac1295140413dc8


### UserInterface

UI を見られるようにするために 適当に nginx に設定書く。下記はざっくりした例。cadviser にも UI があるが cadviser の UI も確認したければ同様に追加すると良い。
簡単に見られると困りそうなので雑に BASIC 認証入れてる。grafana を使う場合にデータソースとして prometheus を指定して利用することになるが、この場合でも grafana の設定で BASIC 認証書けるので問題なし。

```nginx:
upstream prometheus {
  server 172.18.0.2:9090;
}
upstream alertmanager {
  server 172.18.0.4:9093;
}

server {
  listen 80
  server_name prometheus.example.com;
  
  location / {
    proxy_pass http://prometheus;

    auth_basic "Prometheus";
    auth_basic_user_file ".htpasswd";
  }
}
server {
  listen 80
  server_name alertmanager.example.com;
  
  location / {
    proxy_pass http://alertmanager;

    auth_basic "AlertManager";
    auth_basic_user_file ".htpasswd";
  }
}

```

とりあえず .htpasswd 作る例

```
$ cd /etc/nginx/
$ sudo htpasswd -c .htpasswd prometheus
```

###