理想の自宅ラズパイ群監視システムを追い求める長い旅

エンジニアなら自宅に何台かラズパイが稼働していると思いますが、みなさんはこれらの監視をどのように行っていますでしょうか？

今回はラズパイ好きエンジニアが自宅のラズパイたちを監視するために、けっこう真面目に監視システムを構築したお話を紹介します。


# 監視対象
今回作る監視システムで監視したい対象は次の通りです。

- [ラズパイKubernetesクラスター](https://qiita.com/reireias/items/0d87de18f43f27a8ed9b)
  - Kubernetesのメトリクス
  - クラスターを構成する3台のラズパイのメトリクス
- 汎用ラズパイ1台

↓監視したいラズパイたち
![P_20201008_145939.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/943f0d92-aea3-a004-d07b-a9e4f0653e8a.jpeg)


# 監視システムに求める要件
監視システムの要件を洗い出してみます。

- ダッシュボードがある
  - かっこいいダッシュボードが欲しいので
- インターネット越しにアクセスできる
  - 急にダッシュボードを見たくなる時があるので
- インターネットに自宅LANを公開しない
  - セキュリティ面
  - 引っ越しやルーター買い替え時のメンテナンスコストは無くしたい
- 仕事ではないのでコストは極力抑える
  - だいたい月$10以下にしたい

# 監視ツールの選定
まず最初にどんなツールを中心に使うかを検討しました。
興味があり使ってみたいツールは以下の通りでした。

- [Prometheus](https://prometheus.io/)
- [Datadog](https://www.datadoghq.com/ja/)
- [Amazon CloudWatch](https://aws.amazon.com/jp/cloudwatch/)
- [Google Cloud Monitoring](https://cloud.google.com/monitoring?hl=ja)

Prometheusは言わずと知れた最近流行りのPull型メトリクス収集ツールです。主にKubenetersやオンプレミス環境でエコシステムを構築する際に利用されます。使いこなすとかっこいいイメージがあります。
Pull型なので、Prometheus自体から監視対象へアクセスできる必要があります。そのため、LAN内にホストすることになります。

DatadogはSaaS型監視ツールでAgentを可動させたり、IaaSと連携してメトリクスを収集することができます。SaaSなので管理コストが低いのが利点です。

IaaS系はオンプレのメトリクスも送信できるように作られているため、ラズパイからメトリクスを送信することが可能です。しかし、SDK等を用いて実装/設定する部分が多いため今回は優先度は低くなりました。

ということで、Prometheus > Datadog >>> その他 の優先度となったので、Prometheusをメインに利用して構築していくことにしました。


# Prometheusに関する検討
ここからはPrometheusとその周辺ツールに関する内容になります。

## Prometheusの実行環境
Pull型のメトリクス収集ツールなので、Prometheus→各ラズパイの方向のリクエストが到達可能なネットワーク上に構築する必要があります。

![monitoring01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/a1951a6e-e139-c7cf-b120-7961fde93625.png)

そのため、Prometheus自体は自宅LAN内で可動させる必要があります。
専用のマシンを用意しても良いのですが汎用ラズパイがスペック的に余裕があるため、この上でPrometheusを可動させることにしました。

![monitoring02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/eab36ed6-ce57-b9df-5033-1f0d25a73df2.png)


## 収集するメトリクス
ダッシュボードに表示したい内容的に、次のメトリクスが必要となりました。

- Kubernetes
- Kubernetesの各Nodeに使っているラズパイ
- Prometheusを動かす汎用的ラズパイ自身

Kubernetes自体のPodやService数等の取得は[kube-state-metrics](https://github.com/kubernetes/kube-state-metrics)を使います。
ラズパイはCPUがARMなので、ラズパイ上で動くように自分で[ビルド](https://github.com/reireias/kube-state-metrics/commit/16e15da194d035c5cc47f812a82c6bbc3155f7c3)し直しました。

k8sのノードと汎用ラズパイに関しては[Node Exporter](https://github.com/prometheus/node_exporter)を使います。

このあたりの設定はREADMEを見ながら実施できるレベルなのでここでの詳細な紹介は割愛させていただきます。
これで無事にKubenetersの各種メトリクスやラズパイのリソースをPrometheusで取得できるようになりました。

## インターネット越しアクセスの方法
インターネット越しにアクセスできるダッシュボードを用意する方法は2通りありそうです。

**1. SaaSやIaaSなどを利用しダッシュボードをインターネット上に構築する**
Prometheus自身はローカルに独自の時系列データベースをもっていますが、外部にデータを書き出すことが可能です。
[Remote Storage](https://prometheus.io/docs/prometheus/latest/storage/)と呼ばれる機能です。


以下のような構成にすることで、Prometheus自体はLAN内で、Remote Storageとダッシュボードはクラウド側に構築することができます。
通信の方向もPrometheus→Remote Storageとなるので、自宅のLANをインターネットに公開する必要もありません。

また、Remote Storage用のDBとダッシュボードツールを別々に用意せずとも、両方共提供してくれるSaaSを使うという選択肢もあります。

![monitoring03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/6d79f2d8-01c8-463c-7de1-4ba690132325.png)



**2. 何らかの手段で自宅LABにセキュアに接続できる手段を用紙し、LAN内にダッシュボードまで構築する**
もう一つのパターンとしては、ダッシュボードまで自宅のLAN内に構築し、インターネット側からセキュアに自宅LANに接続するという構成です。

![monitoring04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/c838a5f5-2dd4-2c70-2f72-30cae871b961.png)


2のほうは端末単位でアプリのインストールが必要だったりするので、今回はパターン1の方向で検討することとしました。

## Prometheusの構成
ダッシュボードをインターネット上に構築する方針としたので、Prometheus周辺の構成のパターンがある程度絞られてきました。

Remote Storage: SaaS or IaaS
ダッシュボード: SaaS or IaaS

Remote Storageとダッシュボードを選定するために、まずはPrometheusのRemote Starageに対応しているデータベースを確認します。
[公式ドキュメント](https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage)によると以下がRemote Storageに利用できるデータベースの一覧になります。

- AppOptics
- Azure Data Explorer
- Azure Event Hubs
- Chronix
- Cortex
- CrateDB
- Elasticsearch
- Gnocchi
- Google BigQuery
- Google Cloud Spanner
- Graphite
- InfluxDB
- IRONdb
- Kafka
- M3DB
- MetricFire
- New Relic
- OpenTSDB
- PostgreSQL/TimescaleDB
- QuasarDB
- SignalFx
- Splunk
- TiKV
- Thanos
- VictoriaMetrics
- Wavefront

まずはSaaS/PaaS/自前ホストで分類していきましょう。
SaaSに関してはFree Plan(≠無料トライアル)の有無も記載します。

- SaaSあり
  - [AppOptics](https://www.solarwinds.com/ja/appoptics)
      - Free Planなし
  - [Elasticsearch（ElasticC loud）](https://www.elastic.co/jp/cloud/)
      - Free Planなし
  - [InfluxDB](https://www.influxdata.com/)
      - **Free Planあり**
  - [MetricFire](https://www.metricfire.com/)
      - Free Planなし
  - [New Relic](https://newrelic.co.jp/)
      - **Free Planあり**
  - [PostgreSQL](https://www.elephantsql.com/)
      - **Free Planあり**
  - [TimescaleDB](https://www.timescale.com/)
      - Free Planなし
  - [QuasarDB](https://quasardb.net/)
      - Free Planなし
  - [Splunk/SignalFx](https://www.splunk.com/en_us/investor-relations/acquisitions/signalfx.html)
      - Free Planなし
  - [Wavefront](https://tanzu.vmware.com/jp/observability)
      - Free Planなし

- PaaS
  - [Azure Data Explorer](https://azure.microsoft.com/ja-jp/services/data-explorer/)
  - [Azure Event Hubs](https://docs.microsoft.com/ja-jp/azure/event-hubs/event-hubs-about)
  - [Google BigQuery](https://cloud.google.com/bigquery?hl=ja)
  - [Google Cloud Spanner](https://cloud.google.com/spanner?hl=ja)

- 自分でホストする必要あり
  - [Chronix](http://www.chronix.io/)
  - [Cortex](https://www.cortex-ag.com/en/)
  - [CrateDB](https://crate.io/)
  - [Gnocchi](https://gnocchi.xyz/)
  - [Graphite](https://graphiteapp.org/)
  - [IRONdb](https://www.circonus.com/solutions/time-series-database/)
  - [Kafka](https://kafka.apache.org/)
  - [M3DB](https://www.m3db.io/)
  - [OpenTSDB](http://opentsdb.net/index.html)
  - [TiKV](https://github.com/tikv/tikv)
  - [Thanos](https://thanos.io/)
  - [VictoriaMetrics](https://victoriametrics.com/)

### SaaSの検討
やはり可用性が高く管理コストが少ないSaaSを優先して利用したいところです。
有料のものもいくつか確認してみたのですが、やはりログ蓄積系ということで高価なものが多い印象でした。
月$10以下に抑えたいのもあり、無料プランがあるものに関して調査していくことにしました。

n日間のトライアルなどではなく、永続的に無料で利用できるプランがあるのは（今回私が調査した範囲では）下記3つでした。

- [InfluxDB](https://www.influxdata.com/)
- [New Relic](https://newrelic.co.jp/)
- [PostgreSQL](https://www.elephantsql.com/)

InfluxDB時系列データベースのOSSですが、公式がInfluxDB Cloud 2.0というSaaSを提供しています。
InfluxDBの2.0とダッシュボード機能などが利用できます。
↓のようなイケてるダッシュボードも作成できるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/ad332485-fa89-9117-1195-fcb41f8381b2.png)

無料プランでは登録できるデータ量やダッシュボード数に限りはありますが、十分に要件を満たしているようです。
https://www.influxdata.com/influxdb-cloud-pricing/

New RelicはAPMなどを収集できる監視SaaSです。
無料プランでもPrometheus用のエンドポイントを生成でき、ダッシュボード機能も備えているので、こちらも要件を満たしていそうです。
https://newrelic.com/pricing

PostgreSQLのSaaS版として[ElephantSQL](https://www.elephantsql.com/)というサービスがあります。
投入できるデータ量などは制限がありますが、PrometheusのRemote Storageとして使うには十分なように思えます。
当然ダッシュボード機能などはないので、別途ダッシュボードSaaSを利用するか、自分でホストしたダッシュボードから接続する必要がありそうです。
https://www.elephantsql.com/plans.html

## 検証
### InfluxDB Cloud 2.0
さっそく無料プランでアカウントを作成し、PrometheusのRemote Storageを設定してみました。

下記のInfluxDBの公式ドキュメントを参考に設定を行いました。
https://docs.influxdata.com/influxdb/v1.8/supported_protocols/prometheus/

Prometheusサーバーを再起動してみると下記のエラーログが出力されていました。

```
server returned HTTP status 401 Unauthorized:{"code":"unauthorized","message":"unauthorized access"}"
```

いろいろと調べてみたところ、どうやらInfluxDB 2.0が認証に利用するヘッダーと、Prometheusが送信するヘッダーが合っていないようでした。
Prometheusで認証付きのRemote Storageでは下記のように設定します。

```yaml
remote_write:
  - url: https://example.com
    bearer_token: xxxx
```

そうすると、 `Authorization: Bearer xxxx` というヘッダーが付与された状態でエンドポイントへリクエストが投げられます。
一方でInfluxDB 2.0では `Authorization: Token xxxx` という形式が必要となっています。
https://docs.influxdata.com/influxdb/v2.0/reference/api/influxdb-1x/

Prometheus側にIssueが登録されていますが、対応する予定はなさそうでした。
https://github.com/prometheus/prometheus/issues/5657

curlでの接続は成功していたので、このヘッダーをなんとかすればデータ投入できるのでは？と思い、次の方法でヘッダー問題を解決することとしました。

Nginxを間にはさみ、 `proxy_set_header` を使いNginxで `Authorization: Token xxxx` ヘッダーを差し込む方法です。

```
# リクエストの流れ
Prometheus --> Nginx --> InfluxDB Cloud
```

詳細な設定は割愛しますが、この方法で無事にヘッダー認証を突破することができました！！

**が、別のエラーが！**
どうやらPrometheusが投げるクエリ自体がInfluxDB 2.0に対応していないようでした。
(InfluxDB 1.8系にPrometheusで接続したことはあるので、2.0で入ったbreaking changesが原因のようです)

InfluxDB 2.0は比較的最近リリースされたようなので、将来に期待しつつ、いったんはInfluxDB Cloudは諦めることにしました。
https://github.com/influxdata/influxdb/releases

### New Relic
次はNew Relicを試してみました。

無料アカウントを作成し、[公式ドキュメント](https://docs.newrelic.com/docs/integrations/prometheus-integrations/get-started/send-prometheus-metric-data-new-relic)を参考にPrometheus用のEndpointを設定します。
`https://metric-api.newrelic.com/prometheus/v1/write?X-License-Key=xxxx&prometheus_server=prometheus` のようなエンドポイントが生成されるので、これをPrometheus側の `remote_write` に設定します。

これだけでRemote Storageの設定は完了です。
あとはQuery Explorer等で確認しつつ、以下のドキュメントを読みながらダッシュボードを作成するだけです。
https://docs.newrelic.com/docs/query-your-data/nrql-new-relic-query-language/get-started/nrql-syntax-clauses-functions

New RelicではNRQLという独自のクエリ言語と、Prometheus用のクエリ言語である[PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/)の両方が使えます。
実際に触ってみた感じでは内部でPromQLをNRQLに変換して動かしているようです。

最初はNRQLを覚えるのを面倒くさがってダッシュボード用のクエリはPromQLで書いていたのですが、一部変換がうまく動作していない部分があり、思うようにグラフが書けなかったのでNRQLを覚えることにしました。

**そして完成したダッシュボードがこちら。**

![screencapture-one-newrelic-launcher-dashboards-launcher-2020-10-09-17_26_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/87643e5d-6457-bfaa-51a7-7ea0d8fc75ad.png)

いい感じですね。
これをSaaSで無料で実現できるのはとてもありがたいです。

「いったんはここを旅の終着点にしよう」

## 余談
実はSaaSを検討する前に、自前でInfluxDBとGrafanaをホストしてダッシュボードを構築してしばらく運用してました。
実行環境はGCPで無料で使える `f1.micro` インスタンス(1vCPU、0.6GB Mem)上に構築しました。

構成的には下記の図のような形です。
![monitoring05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/14bc7b23-aab7-44b1-b22f-9f2b967b64e4.png)


その時のダッシュボードはこんな感じです。
（New RelicよりGrafanaのほうが個人的には見た目が好き）
![Screenshot from 2020-02-16 23-45-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/1a2c6103-93a1-5218-4fa4-a2249f931838.png)

この構成で数ヶ月運用してみたのですが、以下の点が辛かったです。

- GCEインスタンスの管理(CPUバーストによる課金、ディスク枯渇、メモリ枯渇)が面倒
- NginxのログローテートやInfluxDBのデータの保存期限等を管理する必要がある
- Let's Encryptの初期設定とcronによる更新スクリプトが必要

メモリ枯渇やディスクフルで停止することも何度かあり、**「令和にサーバー管理とかないわ...」**と思いSaaSを利用する方針に切り替えたのでした。

# 実装等
今回の記事に関係するリポジトリを列挙しておきます。
似たような構成を構築する際の参考になれば幸いです。

- https://github.com/reireias/raspberrypi-ansible
  - k8sのノードやPrometheusを動かすラズパイ上の設定を行うAnsibleのコード
  - Node Exporterの設置などもこれで行っています
- https://github.com/reireias/pikube-monitoring-ansible
  - 余談で紹介した、Nginx + InfluxDB + Grafanaを構築するAnsibleのコード
- https://github.com/reireias/kube-manifests
  - ラズパイk8sクラスター用のマニフェストファイル
  - kube-state-metricsの設定はここにかかれています

# まとめ
**サーバー管理したくねえ！！**という想いからPrometheusのRemote StorageとダッシュボードをSaaS化してみました。
みなさんも自宅用の監視システムを構築してみてはいかがでしょうか？