Cloudprober事始め

# Cloudproberとは

Cloudproberは、システムやサービスを監視するためのGoogle謹製のオープンソースモニタリングソフトフェアで、Go言語で実装されています。HTTP、UDP、PING、DNS Probeが組み込みで実装されている他、External Probeという仕組みにより標準入出力でやりとりする外部の実行プログラムを通じてProbe機能をカスタムで拡張できます。Probeの結果はStackDriverとPrometheusにエクスポートできます。さらに、（今回は扱いませんが、）Google Cloud上ではターゲットを自動検出することができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/176968/8e235d34-7594-844f-3ff6-07a0990dd785.png)

**[Google Open Source Blog] Cloudprober: open source black-box monitoring software**
https://opensource.googleblog.com/2018/03/cloudprober-open-source-black-box.html
**cloudprober.org**
https://cloudprober.org/
**Github**
https://github.com/google/cloudprober/

# 前提

この記事では、以下の環境を用いています。

- Ubuntu 16.04.3
- Cloudprober 0.9.3
- Prometheus 2.3.1
- Grafana 5.2.1

# Cloudproberのセットアップ

CloudproberはGo言語で実装されていてバイナリ一つで動作します。プラットフォーム毎にバイナリ化されたものが用意されているので、手っ取り早くこれを使います。

https://github.com/google/cloudprober/releases

```
$ wget https://github.com/google/cloudprober/releases/download/0.9.3/cloudprober-0.9.3-linux-x86_64.zip
$ unzip cloudprober-0.9.3-linux-x86_64.zip
```

## HTTP Probe

手始めに、HTTP Probeを試します。
HTTP Probe用の設定ファイルを用意します。

```text:http_probe.cfg
probe {
  name: "ping-probe-to-google"
  type: HTTP
  targets {
    host_names: "www.google.com"
  }
}
```

Cloudproberのバイナリを展開したディレクトリに移動して、Cloudproberを実行します。

```
$ ./cloudprober -config_file cloudprober.cfg
```

すると、定期的にデータを取得し始めます。
最初の4行分は設定内容にかかわらずデフォルトで取得されるデータのようです。
最後の行がHTTP Probeで取得したデータになります。

```
cloudprober 1531202334854079988 1531202344 labels=ptype=sysvars,probe=sysvars hostname="vagrant"
cloudprober 1531202334854079989 1531202344 labels=ptype=sysvars,probe=sysvars cpu_usage_msec=163.139
cloudprober 1531202334854079990 1531202344 labels=ptype=sysvars,probe=sysvars uptime_msec=10002.874 uptime=10 gc_time_msec=0 mallocs=11847 frees=567
cloudprober 1531202334854079991 1531202344 labels=ptype=sysvars,probe=sysvars goroutines=15 mem_stats_sys_bytes=3903488
cloudprober 1531202334854079992 1531202344 labels=ptype=http,probe=http-probe-to-google,dst=www.google.com total=1 success=1 latency=216295.213 timeouts=0 resp-code=map:code,200:1 resp-body=map:resp
...
```

Cloudproberを動作させると、同時に裏側でPrometheus Exporterが動作します。
ブラウザから`http://<Cloudprobeが動作しているサーバのIP>:9313/metrics`にアクセスすると以下のような結果になります。HTTP Probeと関係ない項目は割愛してます。

```
#TYPE hostname gauge
...
#TYPE total counter
total{ptype="http",probe="http-probe-to-google",dst="www.google.com"} 1 1531202344854
#TYPE success counter
success{ptype="http",probe="http-probe-to-google",dst="www.google.com"} 1 1531202344854
#TYPE latency counter
latency{ptype="http",probe="http-probe-to-google",dst="www.google.com"} 216295.213 1531202344854
#TYPE timeouts counter
timeouts{ptype="http",probe="http-probe-to-google",dst="www.google.com"} 0 1531202344854
#TYPE resp_code counter
resp_code{ptype="http",probe="http-probe-to-google",dst="www.google.com",code="200"} 1 1531202344854
```

## PING Probe

PING Probeは、Root権限が必要なRawソケットとRoot権限の要らないICMP Echoの送受信に制限されたDatagramソケットで動作する2種類があります。

ICMP用途のDatagramソケットで動作させるためのHTTP Probe用の設定ファイルを用意します。

```text:ping_probe.cfg
probe {
  type: PING
  name: "ping-probe-to-google"
  targets {
    host_names: "www.google.com"
  }
  ping_probe {
    use_datagram_socket: true
    source_interface: "eth0"
  }
}
```

ICMP用途のDatagramソケットは多くのシステムでデフォルトでは有効ではないので、以下のようにカーネルパラメータを設定します。

```bash
$ sudo sysctl -w net.ipv4.ping_group_range="0 5000"
```

Cloudproberを実行すると、以下のようになります。PING Probeと関係ない項目は割愛してます。

```bash
$ ./cloudprober -config_file ping_probe.cfg
...
cloudprober 1531207071003333543 1531207081 labels=ptype=ping,probe=ping-probe-to-google,dst=www.google.com total=10 success=10 latency=1513849.826
...
```

## DNS Probe

DNS Probe用の設定ファイルを用意します。

```text:dns_probe.cfg
probe {
  type: DNS
  name: "dns-probe-to-google"
  targets {
    host_names: "8.8.8.8,8.8.4.4"
  }
  dns_probe {
    resolved_domain: "www.google.com."
  }
}
```

Cloudproberを実行すると、以下のようになります。DNS Probeと関係ない項目は割愛してます。

```
$ ./cloudprober -config_file dns_prove.cfg
...
cloudprober 1531207394187566637 1531207404 labels=ptype=dns,probe=dns-probe-to-google,dst=8.8.8.8 total=4 success=4 latency=142839.218 timeouts=0
cloudprober 1531207394187566638 1531207404 labels=ptype=dns,probe=dns-probe-to-google,dst=8.8.4.4 total=4 success=4 latency=164540.74 timeouts=0
```

## PrometheusおよびGrafanaとの連携

最後に、PrometheusおよびGrafanaとの連携を説明します。

それっぽい例として、同じターゲット（www.google.com）に対して、PING ProbeとHTTP Probeを実行します。ユーザーが体感するレスポンスが遅いときに、それがネットワーク側の問題なのか、サービス側の問題なのかを切り分けることができます。出張先のホテルのWIFI環境で試しているためいい具合に（！？）遅延が発生してます。

複数のProbeを設定する方法を一瞬迷いましたが、単純に一つの設定ファイルに複数記述してあげればOKでした。

```text
probe {
  name: "http-probe-to-google"
  type: HTTP
  targets {
    host_names: "www.google.com"
  }
}

probe {
  type: PING
  name: "ping-probe-to-google"
  targets {
    host_names: "www.google.com"
  }
  ping_probe {
    use_datagram_socket: true
    source_interface: "eth0"
  }
}
```

前述のとおりCloudproberはPrometheus Exporterとして動作しているので、Prometheusの設定は以下のようになります。PrometheusはCloudproberと同じサーバで動作している前提です。

```yaml
scrape_configs:
- job_name: 'cloudprober'
  scrape_interval: 10s
  static_configs:
  - targets: ['localhost:9313']
```

あとは、GrafanaのデータソースとしてPrometheusを指定して、グラフを作成します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/176968/67dff648-f010-d947-b67f-5cc1f8848a4b.png)

ちなみに、Grafanaでグラフ作成用に設定したクエリーはそれぞれ以下のとおりです。

**PING Probe**

```
rate(latency{probe="ping-probe-to-google"}[20s])/rate(total{probe="ping-probe-to-google"}[20s])
```

**HTTP Probe**

```
rate(latency{probe="http-probe-to-google"}[20s])/rate(total{probe="http-probe-to-google"}[20s])
```

## トラブルシューティング

実行時に`-logtostderr`フラグを付与すると、ログを標準エラーに出力してくれます。

```
$ ./cloudprober -config_file pg_probe.cfg -logtostderr
```

たとえば、PING Probeで当初`source_interface`を指定していなかったためにうまく動作していませんでした。そのときに、`-logtostderr`フラグ付与したところ、以下のようなログが出力されていたため、設定ミスに気づくことができました。

```
W0709 13:57:39.626037    1731 logger.go:181] write udp 127.0.1.1:10->172.217.8.4:0: sendto: invalid argument
```

おしまい