Helmを使ってPrometheusとGrafanaをデプロイし、Node exporterのメトリクスを可視化する

# はじめに

PrometheusとGrafanaを理解したいのと、稼働している複数のマシンのメトリクス（CPU/メモリ/ストレージ利用率など）を収集したくて、KubernetesのHelmチャートを作って構築してみました。
初めてPrometheusとGrafanaを触った時はDockerやDocker Composeを使って中途半端な状態で終わっていました。今回KubernetesのHelm,Helmfile（本記事では出てきませんが）で改めて構築して一歩前進したので、やったことをまとめます。

# 環境情報

* Kubernetes
    * v1.27.1 （サーバ＆クライアント）
* Helm
    * v3.9.2+g1addefb

ノードは以下のように5台で構築
```
$ kubectl get node -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion,OS-IMAGE:.status.nodeInfo.osImage
NAME            VERSION   OS-IMAGE
control-plane   v1.27.1   Debian GNU/Linux 10 (buster)
node01          v1.27.1   Ubuntu 20.04.6 LTS
node02          v1.27.1   Ubuntu 22.04.1 LTS
node03          v1.27.1   Ubuntu 20.04.6 LTS
node04          v1.27.1   Ubuntu 20.04.6 LTS
```

# やりたいことと実現方針

PrometheusとGrafanaをKubernetesのリソースとしてデプロイし、**各ノードのメトリクスを収集して可視化する**のが目標です。

以下のようにPrometheusとGrafanaのHelmチャートが用意されているので、パラメータを適切に設定し``helm install``コマンドでインストールして実現します。

## Prometheus
https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus
このHelmチャートのメインの機能はPrometheus Serverですが、次の4つの機能のHelmチャートも一緒に（依存関係的に）インストールされます。

* alertmanager
* kube-state-metrics
* prometheus-node-exporter
* prometheus-pushgateway

筆者の知識不足もあって4つ全てを説明できませんが、少なくともprometheus-node-exporterが各ノードのメトリクスを収集し、本記事の目標達成に貢献してくれます。

※詳細未確認ですが、kube-state-metricsでKubernetesのメトリクスも収集できそうです！


## Grafana

https://github.com/grafana/helm-charts/tree/main/charts/grafana

Prometheus Serverと連携して、Node exporter等が提供したメトリクスをいい感じで可視化してくれます。可視化部分は自分でクエリやダッシュボードを作って実現もできますが、既に公開されているNode exporterのダッシュボードを使うのが速いので今回はそれを使う方針にします。

## 全体像の中での位置づけ

公式サイトに出ているアーキテクチャーの図で対応づけて考えると、今回は以下の機能を使うことになります。
* Job/exporters（左下）
    * Node exporterを使って各ノードのメトリクスを収集
* Prometheus Server（真ん中）
    * Node exporterにメトリクス等の情報の収集命令を出す
    * 収集した情報をHTTPサービスとして提供する
* Grafana（右下）
    * Prometheus Serverが提供した情報を取得して可視化する

<img width="100%" src="https://prometheus.io/assets/architecture.png">

# PrometheusのHelmチャートのデプロイ

## Helmリポジトリの追加
[README](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus#readme)に書かれた通りに、prometheus-communityのHelmリポジトリを追加します。

```
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
```

## PersistentVolume関連のパラメータ設定
prometheus-serverとprometheus-node-exporterに関しては、PersistentVolumeを使う設定がデフォルトになっています。そこで例えば変数定義ファイルを以下のように作り、StorageClassをで指定する必要があります。

```yaml:values-prometheus-local.yaml
server:
  persistentVolume:
    storageClass: <prometheus-server用のSC名>
alertmanager:
  persistence:
    storageClass: <prometheus-node-exporter用のSC名>
```
StorageClassがない環境であれば、以下のようにPersistentVolumeを使わない設定にすればOKです。
ただし、この設定だと**Podを消したら各サービスが収集したメトリクス等の情報も（おそらく）消えてしまう**のでご注意ください！

```yaml:values-prometheus-local.yaml
server:
  persistentVolume:
    enabled: false
alertmanager:
  persistence:
    enabled: false
```

## デプロイ

以下のコマンドを実行します。

```shell
helm install --create-namespace --namespace prometheus \
prometheus prometheus-community/prometheus \
-f values-prometheus-local.yaml \
--version 24.1.0
```
数分ほど待ち、Podがデプロイされていることを確認します。以下のようにNode exporterがDaemonSetリソースとして各ノードにデプロイされていることがわかります。
（筆者環境だとNode exporterがcontrol-planeにもデプロイされていますが、デフォルトだとWorkerノードにしか作られないはずです）

```
$ kubectl get pod -n prometheus -o custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[0].ready,STATUS:.status.phase,NODE:.spec.nodeName
NAME                                                 READY   STATUS    NODE
prometheus-alertmanager-0                            true    Running   node01
prometheus-kube-state-metrics-b4557d966-9f2r9        true    Running   node01
prometheus-prometheus-node-exporter-6tn6r            true    Running   node04
prometheus-prometheus-node-exporter-dpp5w            true    Running   control-plane
prometheus-prometheus-node-exporter-gwqg6            true    Running   node03
prometheus-prometheus-node-exporter-vfhlt            true    Running   node01
prometheus-prometheus-node-exporter-xcvs9            true    Running   node02
prometheus-prometheus-pushgateway-79ff799669-mgzjc   true    Running   node01
prometheus-server-7f8bb747c4-wwk5t                   true    Running   node02
```
また、Serviceリソースが以下のように作られています。次の手順で``prometheus-server``のServiceをGrafanaと連携します。
```
$ kubectl get svc -n prometheus
NAME                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
prometheus-alertmanager               ClusterIP   10.107.241.238   <none>        9093/TCP   6d14h
prometheus-alertmanager-headless      ClusterIP   None             <none>        9093/TCP   6d14h
prometheus-kube-state-metrics         ClusterIP   10.104.23.189    <none>        8080/TCP   6d14h
prometheus-prometheus-node-exporter   ClusterIP   10.107.210.162   <none>        9100/TCP   6d14h
prometheus-prometheus-pushgateway     ClusterIP   10.103.56.16     <none>        9091/TCP   6d14h
prometheus-server                     ClusterIP   10.101.118.171   <none>        80/TCP     6d14h
```

# GrafanaのHelmチャートのデプロイ

## Helmリポジトリの追加
[README](https://github.com/grafana/helm-charts/tree/main/charts/grafana#readme)に書かれた通りに、grafanaのHelmリポジトリを追加します。

```
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
```

## Datasource,Dashboardのパラメータ設定

Grafanaをデプロイした際に、既にデプロイしたPrometheus Serverが連携され、かつNode exporterで収集したメトリクスがダッシュボードで見えるようにしたいです。これらの設定はGrafanaをデプロイした後にWebUI上でも行うことができますが、この方法だとGrafanaを更新した際などに設定が消えてしまうのであまり賢明ではありません。
そこで、以下のような変数定義ファイルを用意して設定が常に保持されるようにします。

```yaml:values-grafana-local.yaml
# クラスター外からアクセスできるようにする一つの手段
service:
  type: NodePort

# (1) Prometheus Serverとの連携
datasources:
 datasources.yaml:
   apiVersion: 1
   datasources:
    - name: "Prometheus"
      type: prometheus
      access: proxy
      url: http://prometheus-server.prometheus.svc.cluster.local

# (2) Dashboardの基本設定
dashboardProviders:
  dashboardproviders.yaml:
    apiVersion: 1
    providers:
    - name: 'default'
      orgId: 1
      folder: ''
      type: file
      disableDeletion: false
      editable: true
      options:
        path: /var/lib/grafana/dashboards/default

# (3) Node exporterのDashboardを追加する設定
dashboards:
  default:
    node-exporter:
      datasource: Prometheus
      url: https://grafana.com/api/dashboards/1860/revisions/32/download
```

以下簡単に解説します。

### (1) Prometheus Serverとの連携

Prometheus ServerのServiceリソース``prometheus-server``と連携するための設定です。Namespaceが``prometheus``なので、``http://prometheus-server.prometheus.svc.cluster.local``と指定すればクラスター内でアクセス可能です。


### (2) Dashboardの基本設定

筆者があまり理解できていない部分ですが、[こちら](https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml#L659)の内容をそのまま使わせてもらいました。

### (3) Node exporterのDashboardを追加する設定

"Node Exporter Full" というダッシュボートが下記から提供されています。

https://grafana.com/grafana/dashboards/1860-node-exporter-full/

このサイトの右下の「Download JSON」のURLを``url: ``に記載して、デプロイ時にインポートするようにします。

## デプロイ

以下のコマンドを実行します。

```shell
helm install --create-namespace --namespace grafana \
grafana grafana/grafana \
-f values-grafana-local.yaml \
--version 6.59.0
```

Grafanaが稼働しているのを確認します。

```
$ kubectl get pod -n grafana
NAME                       READY   STATUS    RESTARTS   AGE
grafana-5c4798c889-fnwr8   1/1     Running   0          2m13s
```
``grafana``のServiceリソースはNodePortとして動いているので、3xxxx系の任意のポート番号が割り振られます。
```
$ kubectl get svc -n grafana
NAME      TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
grafana   NodePort   10.110.8.136   <none>        80:3xxxx/TCP   2m44s
```


# WebブラウザでGrafanaに接続して確認

## ログイン

Webブラウザで以下のURLにアクセスします。（3xxxxは``grafana``のServiceリソースに任意に割り当てられるポート番号です）

http://[ノードのIPアドレス]:3xxxx

以下のログイン画面が表示されます。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/f12ffe70-57e6-6b0e-864e-9ad20c158b73.png">

ユーザ名とパスワードは``grafana``というSecretリソースに格納されており、以下のコマンドで確認できます。

```
$ kubectl get secret -n grafana grafana -o jsonpath="{.data.admin-user}" | base64 -d
(出力結果)
admin
```

```
$ kubectl get secret -n grafana grafana -o jsonpath="{.data.admin-password}" | base64 -d
(出力結果)
xxxx....
```

## Data sourceの連携確認

左メニューの"Connections"を選択後、"Data sources"をクリックし、以下のようにPrometheusのdata sourceが表示されることを確認します。
![スクリーンショット 2023-09-10 8.50.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/b96d5bdf-e9af-bc75-5b99-893ff963b67d.png)
ちゃんと接続できるかまで確認したいのであれば、Prometheusをクリック後、Settings画面で一番下まで遷移し、"Save & test"のボタンをクリックして以下のように"Successfully queried the Prometheus API."とメッセージが出ればOKです。

![スクリーンショット 2023-09-10 8.55.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/77ccec70-b54f-df2d-1123-cabd86cde0f9.png)


## Dashboardのインポート確認

左メニューの"Dashboards"をクリックして、以下のようにGeneralフォルダに"Node Exporter Full"がインポートされていることを確認します。

![スクリーンショット 2023-09-10 8.57.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/c8aa1eec-db71-dab3-d5c1-a25e4d0fc39c.png)

"Node Exporter Full"をクリックして、以下のようなDashboardが表示されたら成功です！

![スクリーンショット 2023-09-10 9.03.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/e3cdce74-e19b-9f4d-d082-b24f3fdc67db.png)