Pongo利用時にPrometheus/Grafanaも自動で起動する

Kong GatewayのカスタムプラグインのテストツールであるPongoを使ってプラグイン開発する際に、Prometheus/Grafanaで性能を確認したいことがあると思う。
今回はPongo利用時に自動でPrometheus/Grafanaが起動するようにする方法をまとめる。

## 仕組み
Pongoの[Custom local dependencies](https://github.com/Kong/kong-pongo?tab=readme-ov-file#custom-local-dependencies)という仕組みを使って実現する。
これを使うと、Pongo起動時に.pongo配下のDocker ComposeのYAMLを読み込み、自動でPrometheus/Grafanaが起動するようになる。
これを設定するには以下を行う。

- Prometheusの追加
  1. `.pongo/prometheus.yml`を作成する
  2. `.pongo/pongorc`に`--prometheus`を追加する
- Grafanaの追加
  1. `.pongo/grafana.yml`を作成する
  2. `.pongo/pongorc`に`--grafana`を追加する

作成の際の注意点としては以下となる。
- 命名規則がある
    - `.pongo/<service-name>.yml`という形式で作成する
    - pongorcに`--<service-name>`を追加する
    - YAML内のサービス名は`<service-name>`と同じにする
- ネットワーク名は`${NETWORK_NAME}`で指定する
- ファイルを持ち込みたい場合は`${PONGO_WD}`がカスタムプラグインのルートディレクトリを指すので、これを使ってマウントする

実際にやってみた。

## Prometheusの追加
最初にPrometheusのスクレイピングの設定となるprometheus.ymlを作成する。
```yaml:prometheus.yml
cat <<EOF > ./prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  - job_name: 'kong'
    static_configs:
      - targets: ['kong:8001']
EOF
```
Pongoのテストで使うKong Gatewayは`kong:8001`でAdmin APIを公開し、`/metrics`でメトリクスを公開する。通常の運用においてはRBACがあるとスクレイプ出来ないのでStatus APIを使った方がよいが、PongoではRBACは利用しない事が多いと思うので一旦Admin APIを使って公開する。
この設定でPrometheusがKong Gatewayのメトリクスをスクレイピングするようになる。

次に.pongoディレクトリにprometheus.ymlを作成する。
```yaml:.pongo/prometheus.yml
cat <<EOF > .pongo/prometheus.yml
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ${PONGO_WD}/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
    - ${NETWORK_NAME}
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:9090/-/ready"]
      interval: 30s
      timeout: 10s
      retries: 3
EOF
```
次にpongorcに`--prometheus`を追加する。
```sh:.pongo/pongorc
cat <<EOF >> .pongo/pongorc
--prometheus
EOF
```
以上でPrometheusの準備は終了となる。

## Grafanaの追加
Grafanaも最初は同様に設定ファイルを作成する。
Grafanaでは以下のファイルを用意し、起動時の設定の手間を省く。
- ダッシュボード（JSON）
- データソースの設定（YAML）
- ダッシュボードの配置設定（YAML）

それらを配置するためのディレクトリを作成する。
```sh
mkdir -p ./grafana/{dashboards,provisioning,datasources}
```
ダッシュボードのJSONは[こちら](https://grafana.com/grafana/dashboards/7424-kong-official/)からダウンロードしたファイル(7424_rev11.json)を./grafana/dashboards/以下に配置する。

データソースの設定は以下のようにした。
```json:./grafana/datasources/datasources.yml
cat <<EOF > ./grafana/datasources/datasources.yml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    orgId: 1
    uid: prometheus
    url: http://prometheus:9090
    isDefault: true
    version: 1
    editable: true
EOF
```
ダッシュボードの配置設定は以下のようにした。
```json:./grafana/provisioning/dashboards.yaml
cat <<EOF > ./grafana/provisioning/dashboards.yaml
apiVersion: 1
providers:
  - name: 'Kong'
    orgId: 1
    folder: 'Kong'
    type: file
    disableDeletion: false
    updateIntervalSeconds: 10
    allowUiUpdates: false
    options:
      path: /var/lib/grafana/dashboards/7424_rev11.json
      foldersFromFilesStructure: false
EOF
```

次に.pongoディレクトリにgrafana.ymlを作成する。
```yaml:.pongo/grafana.yml
cat <<EOF > .pongo/grafana.yml
services:
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    volumes:
      - ${PONGO_WD}/grafana/dashboards:/var/lib/grafana/dashboards
      - ${PONGO_WD}/grafana/datasources:/etc/grafana/provisioning/datasources
      - ${PONGO_WD}/grafana/provisioning:/etc/grafana/provisioning/dashboards
    ports:
      - "3000:3000"
    networks:
      - ${NETWORK_NAME}
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
EOF
```

以上で必要なファイルは作成できた。
## 動作確認

`pongo up`を実行し、依存関係のあるコンテナ、すなわち今回依存関係を作り込んだPrometheus/Grafanaを起動する。
```sh
pongo up
```
問題なければ以下のようなメッセージが確認できる。
```sh
 ✔ Container prometheus  Started                                                               0.2s
 ...
 ✔ Container grafana  Started                                                                  0.3s
```
もうこのタイミングでPrometheus/Grafanaにはアクセスできる。
次に動作確認のためにKongコンテナを起動する。
```
pongo expose
pongo shell
```
シェル起動後、`kms`を実行してKongを起動する。
```sh
kms
```
Service、Routeを作成し、Prometheus Pluginを導入する。
ここではコンテナ内からではなく、exposeしたポートを利用して別端末からlocalhost宛にhttpコマンドでAPIを発行して作成した。
```sh
http POST :8001/services name=example-service url=http://httpbin.org
```
```sh
http POST :8001/services/example-service/routes name=example-route paths:='["/echo"]'
```
```sh
http -f :8001/routes/example-route/plugins name=prometheus \
  config.status_code_metrics=true \
  config.latency_metrics=true \
  config.bandwidth_metrics=true \
  config.per_consumer=true \
  config.upstream_health_metrics=true
```
メトリクスが取れているか確認するために、以下のような感じでリクエストを投げ続ける。
```sh
watch http localhost:8000/echo/ip
```
### Prometheus側の動作確認
[http://localhost:9090](http://localhost:9090)にアクセスすると、PrometheusのUIにアクセスできる。
Target healthを見ると以下のような感じで正常にスクレイプできていることが分かる。
![20250318155347.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0d3d1754-64da-4bc5-8b1b-e0454e292da1.png)

適当にPromQLを発行し、メトリクスが届いていることも確認できる。
![20250318155513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b75f95e7-baaa-459f-88c3-1d17ed9700cb.png)


### Grafana側の動作確認
[http://localhost:3000](http://localhost:3000)にアクセスすると、GrafanaのUIにアクセスできる。
ログイン画面が表示されるので、デフォルトの`admin`/`admin`でログインする。
ログインしてDashboardを選択するとダッシュボードの配置設定で指定したフォルダにKongのダッシュボードがあることが分かる。
![20250318155650.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/53cbd793-a03f-44b3-be04-5ed9c6f94c3a.png)

ダッシュボードを見てみると、先程送信したリクエストのメトリクスが表示されていることが分かる。
![20250318155740.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/9369fef9-6338-4b25-8488-d8149f0d207e.png)

## まとめ
ということで、Pongo利用時にPrometheus/Grafanaを起動する方法を紹介した。
これよりPongoでプラグイン開発する際に簡単にPrometheus/Grafanaを用意でき、ちょっとした性能確認とか調査とかに活用できるようになる。