Grafana Agent によるメトリクス収集と Grafana による可視化に入門する


## 目標

Prometheus などを全く触ったことがないのですが、Grafana の使い方を勉強することにしました。  
学習のために、Grafana Agent でサーバーのメトリクスを収集し、それを別のサーバーの Prometheus に送信し、 Grafana によって可視化します。  
メトリクス送信先の Prometheus と Grafana は docker compose で立ち上げます。

## Grafana Agent とは

オープンソースの軽量メトリクスコレクターです。Grafana という名前がついていますが、Grafana や Grafana Cloud との連携が必須なわけではないです。  
このような用途だと Prometheus のほうが有名と思われますが、Grafana Agent は

> Batteries included: Integrate with systems like MySQL, Kubernetes, and Apache to get telemetry that’s immediately useful.

とあった（[Grafana Agent のドキュメント](https://grafana.com/docs/agent/latest/)）ので、素の Prometheus よりも簡単なのではないかと思い、興味を持ちました。  
また、まだ試していないですが、loki でログを収集したり、Pyroscope でアプリケーションのプロファイリングをしたりすることも Grafana Agent 単体でできそうで、ポテンシャルを感じます。

### Grafana Agent Flow

Grafana Agent には

- Static mode
- Static mode Kubernetes operator
- Flow mode

の 3 種類があります。今回試したのは Flow mode です。  
Flow mode は 2022 年に登場したばかりで上記の中で一番新しいですが、Grafana Agent の[ドキュメント](https://grafana.com/docs/agent/latest/)では登場が古い Static mode よりも機能が多そうな印象です。例えば、Pyroscope によるプロファイリングは Static mode でなく、Flow mode でしか使えないとされています。  
Prometheus は収集した情報を蓄積する機能を持ち、オプションで、自身に情報を蓄積するのではなく、外部に送信する機能（remote_write）も持つものだと思います。しかし、私がドキュメントを読んだり、動作させてみたりする限り、Flow mode は情報を蓄積する機能は基本的に持たず、remote_write するのが前提になっている気がします。このことはかなり重要な特性だと思いますが、ドキュメントで明言している箇所を見つけられません。私の誤解である可能性もありますが……。  
ともかく、今回は Grafana Agent をサーバーにインストールするだけでなく、そのメトリクスを受信するための Prometheus も別サーバーに立ち上げることにしました。

## Prometheus と Grafana

Grafana と Prometheus は有名だと思うので、説明は省略しますが、Prometheus は自身で情報を収集する通常の使い方を目的とせず、外部からのメトリクスの書き込みリクエストを受付け、蓄積するために使います。  
Grafana はその Prometheus に蓄積された情報の可視化に利用します。

## 動作させてみる

### Prometheus と Grafana の起動

まず Prometheus と Grafana を docker compose で起動します。
docker-compose.yml は次のようにしました。

```yaml
services:
  prometheus:
    image: prom/prometheus:v2.47.0
    container_name: prometheus
    command:
      - --web.enable-remote-write-receiver
      - --config.file=/etc/prometheus/prometheus.yml
      - --log.level=debug
    ports:
      - "9090:9090"
  grafana:
    image: grafana/grafana-enterprise:10.2.4
    container_name: grafana
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
      - GF_USERS_DEFAULT_THEME=light
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /etc/grafana/provisioning/datasources
        cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
        apiVersion: 1
        datasources:
        - name: Prometheus
          type: prometheus
          orgId: 1
          url: http://prometheus:9090
          basicAuth: false
          isDefault: true
          version: 1
          editable: true
        EOF
        /run.sh
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
```

`docker compose up -d`で起動します。目当ての情報は蓄積されていませんが、`localhost:3000`にアクセスすると Grafana の Web UI を確認できます。

設定は Grafana Agent Flow model のドキュメントの[Get started](https://grafana.com/docs/agent/latest/flow/tutorials/flow-by-example/get-started/)のものを参考にしました。

prometheus コンテナには command に 3 つのコマンドライン引数を指定していますが、意味は次のとおりです。

| 引数名                                         | 説明                                                                                                                               |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `--web.enable-remote-write-receiver`           | Prometheus が remote-write リクエストを受け入れるために必要です。                                                                  |
| `--config.file=/etc/prometheus/prometheus.yml` | 起動に必要な設定ファイルを指定します。今回は`prometheus.yml`はデフォルトのまま変更していませんが、指定していと起動しませんでした。 |
| `--log.level=debug`                            | 動作確認のために詳細なログを出力するために指定します。デフォルトは info で通常は debug レベルのログ出力は不要でしょう。            |

Prometheus コンテナは 9090 ポートを expose していますが、これは外部からのメトリクスの remote_write を受け付けるためです。

Grafana コンテナの方は entrypoint で yaml ファイルを作成しています。  
これは`/etc/grafana/provisioning/datasources/ds.yaml`というディレクトリの名前通り Grafana のデータソースを設定してます。  
Grafana の Web UI の`/connections/datasources`にアクセスすると、最初から Prometheus との接続がセットアップされていることを確認できます。

![/connections/datasourcesにおけるデータソース設定画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/006e0132-5a8a-3a4f-4314-9c31f62165d3.png)

docker-compose.yml で設定するのは必須ではなく、起動後、この画面右上の「Add new data source」ボタンから接続設定を追加することも可能です。

### Grafana Agent の起動

先程 Prometheus と Grafana を起動したのとは別のサーバーに Grafana Agent を導入します。  
Kubernetes などでなく、Linux サーバーに直接インストールする方法はドキュメントの[Install or uninstall Grafana Agent Flow on Linux
](https://grafana.com/docs/agent/latest/flow/get-started/install/linux/#install-or-uninstall-grafana-agent-flow-on-linux)で紹介されています。これをそのまま実行しました。

### Grafana Agent の設定ファイル修正

先述の方法で導入した場合、Grafana Agent の設定ファイルは`/etc/grafana-agent-flow.river`にあります。  
これを次のように書き換えます。（設定ファイルにはサンプル設定が記載されていますが、全て消してしまいました）

```bash
prometheus.exporter.unix "default" {
    include_exporter_metrics = false
}

prometheus.scrape "node" {
    targets = prometheus.exporter.unix.default.targets
    forward_to = [prometheus.remote_write.hq.receiver]
    scrape_interval = "15s"
}

prometheus.remote_write "hq" {
  endpoint {
    url = "http://xxx.compute.amazonaws.com:9090/api/v1/write"
  }
}
```

`prometheus.exporter.unix`などの各コンポーネントの意味は[Components reference](https://grafana.com/docs/agent/latest/flow/reference/components/)、設定ファイル（river ファイル）全般については[Concepts](https://grafana.com/docs/agent/latest/flow/concepts/)以下のページにあります。

今回の設定ファイルの意味合いは簡単に説明すると次のとおりです。

- prometheus.exporter.unix "default"
  - いわゆる`node_exporter`を利用するための設定です。Unix 系のシステムメトリクス全般を収集します。include_exporter_metrics = false という設定は、エクスポーター自体のメトリクスを収集対象から除外することを意味します。つまり、このエクスポーターはシステムのメトリクスのみを収集し、自身のパフォーマンスメトリクスは収集しないように設定されています
- prometheus.scrape "node"
  - Grafana Agent がメトリクスを収集するためのスクレイプ設定です。targets = prometheus.exporter.unix.default.targets は、上述の`prometheus.exporter.unix`が提供するターゲット（収集対象）からメトリクスを収集することを指定しています
  - forward_to = [prometheus.remote_write.hq.receiver]は収集したメトリクスをどこに転送するかを指定します。この場合、後述の hq という名前のリモートライト設定に転送されます
  - scrape_interval = "15s"は、メトリクスを収集する間隔を 15 秒に設定しています
- prometheus.remote_write "hq"
  - 収集したメトリクスをリモートのエンドポイントに送信するための設定です。`endpoint { url = "http://xxx.compute.amazonaws.com:9090/api/v1/write" }`は、収集したメトリクスを送信する先の URL を指定しています。先程の項目で docker compose で立ち上げた Prometheus に接続できるように設定します。私は AWS EC2 で立ち上げたので、このような URL にしましたが、もちろん環境によって変わります

設定を書き換えたあとは`grafana-agent-flow`サービスを再起動します。

```bash
sudo systemctl reload grafana-agent-flow
```

次のコマンドで Grafana Agent のステータスを確認できます。

```bash
sudo systemctl status grafana-agent-flow
```

下記のようなログが`systemctl status`で表示され、メトリクスが Prometheus へ送信されたことを確認できます（reload から少し待つ必要がありました）

```bash
level=info msg="Done replaying WAL" component=prometheus.remote_write.hq subcomponent=rw remote_name=cfff9b url=http://xxx.compute.amazonaws.com:9090/api/v1/write duration=30.003717745s
```

### Grafana でメトリクスの確認

Prometheus で受信したメトリクスを Grafana で確認してみます。  
自力でダッシュボードを作成するのは大変なので、既成のダッシュボードを import して利用してみます。  
[Node Exporter Full](https://grafana.com/grafana/dashboards/1860-node-exporter-full/)というダッシュボードを利用します。ID:1860 をコピーします（画面の「Copy ID to clipboard」ボタンでできます）

![Node Exporter Fullの紹介ページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/3d86550b-74b6-371c-ad99-2da3210ef33a.png)

その後、自分で立ち上げた Grafana で作業します。

`/dashboards`にアクセス、もしくは左のハンバーガーメニューから`Dashboards`へアクセスします。

![Dashboards画面へアクセスする](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/1b7ca808-19f2-5d21-9043-ff5157f664c2.png)

遷移先は Dashboards 一覧ページです。まだ何もダッシュボードがありません。右上の New ボタン →Import とクリックします。

![ダッシュボード一覧画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/bb318e02-b4b5-28b8-3b9d-1b1e75d52d6a.png)

ダッシュボードを import できる画面になるので、先程の「Node Exporter Full」の ID である 1860 を入力して Load します。

![ダッシュボード入力画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/cb4840ee-df18-2a26-5ebd-2651797dca94.png)

これでダッシュボードが作成されたので、確認します。インポートすると、ダッシュボードの画面に遷移した気もしますが、先述のダッシュボード一覧画面にもインポートしたダッシュボードが表示されるようになったはずなので、そこからでもアクセスできます。

ダッシュボードを確認すると Grafana Agent をインストールしたサーバーの情報が一覧で表示されているはずです。

![node_exporter_fullのダッシュボード画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/69618399-1b36-4896-d6c6-9d969f9534dc.png)

## トラブルシュート

簡単な手順ですが、これだけのことを実現するのに私はだいぶ苦労しました……。何かうまく行かなかったときに手がかりとなりそうなポイントを紹介します。

### Grafana Agent のログ

Grafana Agent は systemd のサービスとして起動しているため、次のようなコマンドでステータス、ログを確認できます。

```bash
sudo systemctl status grafana-agent-flow
sudo journalctl -u grafana-agent-flow.service
```

### Grafana Agent の Web UI

実は Grafana Agent 自体にも Web UI があります。12345 ポートでアクセスできます。

![Grafana Agent Web UI画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/aab040fe-530a-d963-afd1-746b14abe078.png)

### Prometheus の Web UI

Prometheus 自体にも Web UI があります。9090 ポートでアクセスできます。通常時は Grafana で可視化すると思いますが、問題の切り分けで使えるかもしれません。

![Prometheus Web UI画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273742/2ca574e1-e90d-399d-4d9b-7858ec5ab628.png)