IK.AM

@making's tech note


Pivotal Application Service上のアプリメトリクスをPrometheusでScrapeする方法

🗃 {Dev/PaaS/CloudFoundry/PCF/Monitoring}
🏷 Cloud Foundry 🏷 Pivotal Cloud Foundry 🏷 Prometheus 🏷 Promregator 🏷 Spring Boot 🏷 Micrometer 🏷 RSocket 
🗓 Updated at 2019-09-02T02:14:13Z  🗓 Created at 2019-08-21T03:58:30Z   🌎 English Page

Pivotal Application Service (Cloud Foundry)上にデプロイしたアプリケーションのメトリクスをPrometheusからScrapeしたい時の問題と2019年8月時点での解決法について説明します。

目次

問題

例えばhttps://example.apps.my-paas.example.comにルーティングされるアプリケーションに対する次のようなScrape Configを設定したとします。

scrape_configs:
- job_name: example
  scrape_interval: 60s
  scrape_timeout: 10s
  scheme: https
  static_configs:
  - targets:
    - example.apps.my-paas.example.com:443
  metrics_path: /actuator/prometheus

この設定はexampleアプリが1インスタンスの場合は問題ありません。ところが2以上にスケールアウトした場合は、 次の図で示されるようにGoRouterによってラウンドロビンされるため、Prometheusはどれか1インスタンスのメトリクスを順番に保存していくため、全インスタンスのメトリクスを取得するということができません。 例えばcf_instance_idのようなインスタンス単位で一意なラベルを付与してもちぐはぐなグラフになってしまいます。

image

GoRouterを経由して特定のインスタンスにアクセスしたい場合は、ドキュメントに記載されているように、X-CF-APP-INSTANCEヘッダーにYOUR-APP-GUID:YOUR-INSTANCE-INDEXを指定する必要があります。 例えばexampleアプリの0番目のインスタンスにcurlでアクセスしたい場合は、-H "X-CF-APP-INSTANCE: $(cf app example --guid):0"を付与します。

PrometheusのConfigでこのヘッダーを設定することは出来ません。

解決法

この課題に対して、いくつか解決方法(回避方法?)があります。

TODO: Push Gatewayについても書く

Promeregator

Promregatorは名前の通り、"Prometheus Aggregator"の役割を担います。PAS 2.3まではこれを使わざるを得ませんでいた。

PromregatorはCAPIにアクセスすることでApp GUIDを取得し、全インスタンスのメトリクスエンドポイントに対してX-CF-APP-INSTANCEヘッダーを付与してアクセスします。 PromethesuはPromregatorに対して集約されたメトリクスを取得します。

image

Promregatorはcf pushでデプロイすることも出来ますが、この場合はスケールアウトはできません。 デプロイ方法はこちらの記事を参考にしてください。 Promregator自体をスケールアウトしたい場合は、VMやKubernetes上に置く必要があります。

Metric Registrar

PAS 2.4からMetric Registrarが導入されました。これは直接Prometheusがアプリのメトリクスエンドポイントにアクセスするのではなく、Doppler上のMetric Registrar Endpoint Workerが全インスタンスのメトリクスエンドポイントに対してX-CF-APP-INSTANCEヘッダーを付与してアクセスします Metric Registrar Endpoint WorkerがScrapeしたメトリクスは変換されFirehoseに送られます。Firehoseから再びPrometheusにメトリクスを保存する方法は後述します。

image

アプリ毎のメトリクスエンドポイントの定義はドキュメントで説明されているように、CF CLIのプラグインであるMetric Registrar CLIを使って行います。

exampleアプリの/actuator/prometheusをScrapeして欲しい場合は、次のコマンドで設定できます。

cf register-metrics-endpoint example /actuator/prometheus

このコマンドはこの記事の作成時点では次のコマンドと等価です。

cf create-user-provided-service metrics-endpoint-actuator-prometheus -l metrics-endpoint:///actuator/prometheus
cf bind-service example metrics-endpoint-metrics

将来的には実装が変わる可能性があるので、cf register-metrics-endpoint でサービスインスタンスを作ってサービスインスタンス名をmanifest.ymlserviecsフィールドに追加しておくのが良いでしょう。

制約としては、Metric Registrar Endpoint Workerに認証情報を渡す方法がなく、エンドポイントに認証を設定することができません。 Workaroundとしては、PrometheusエンドポイントへのアクセスをDoppler VMのIPからのみ許可するように設定することで一般ユーザーにアクセスされることを防げます。

Spring Securityの場合はhasIpAddressでホワイトリストの設定が可能です

この制約を許容できない場合は、Structured Log Formatで代替できます。 この場合はPrometheusエンドポイントを用意する代わりに、DogStatsD形式またはJSON形式でメトリクスをログとして標準出力に出力すれば、Firehoseに転送できます。

image

Micrometerを使っている場合はStatsD RegistryのDatadog Flavorを使用し、lineSinkメソッドで標準出力にメトリクスを出力すれば良いです。

Firehoseに送られたメトリクスをPrometheusに保存するにはExporterが必要です。Firehose -> PrometheusのExporterとしては次の2つがあります。

PASを使う場合はReliability View Exporter for PASを使えば良いと思います。

Firehose Exporeterはメトリクス名にPrefixが付くため、Grafana Dashboardが作りにくいです。

PrometheusのScrape ConfigにはこのExporterの設定を行えば良いです。次の図のような構成になります。

image

Firehoseに送らられたメトリクスはPrometheus CompatibleなMetric Storeに長期間保存することができます。

Metric Storeはこちら。

OSS版はSingle NodeでEnterprise版はMulti Nodes/HAに対応しています。

この場合はGrafanaからPrometheusデータソースとして直接Metric Storeを登録可能です。

image

Metric StoreはUAAと連携して、Developerがデプロイしたアプリのメトリクスのみ取得できるように認可制御させることもできます。 Grafanaの設定方法はこちらを参照してください。

Metrics Registrarはデフォルトで、deploymentjobindexidタグ(Prometheusのラベル)を取り除いてFirehoseに送ります。
Micrometerを使っている場合はidタグはメトリクスを区別するのに重要な情報なので、Blacklisted Tagsからidを除外してください
image

Prometheus RSocket Proxy

最も新しい解決方法がPrometheus RSocket Proxyです。

RSocketプロトコルを使用して、アプリとPrometheus Proxyが双方向に通信します。 PromethesuはPrometheus RSocket Proxyに対して集約されたメトリクスを取得します。

Promregatorと少し似ていますが、Promregatorとは異なり、Prometheus RSocket ProxyからアプリへのアクセスはLoad BalancerやGoRouterや経由せず直接通信になります。

image

Micrometerの使用が前提なので、Javaアプリに限られます。JavaアプリにPrometheus RSocket Proxyのクライアントライブラリを追加する必要があります。 Spring BootのAutoConfigurationも用意されていますが、Spring Boot 2.1以上が対象です。

PrometheusからPrometheus RSocket ProxyへのアクセスはHTTP(S)ですが、アプリからPrometheus RSocket ProxyへのアクセスははTCPです。

Prometheus RSocket ProxyはTCP Routerを使うことで、cf pushでデプロイすることも出来ますが、この場合はスケールアウトはできません。 Prometheus RSocket Proxy自体をスケールアウトしたい場合は、VMやKubernetes上に置く必要があります。Kubernetes上にデプロイし、 Horizontal Pod Autoscalerを設定することが推奨されているようです。

Prometheus RSocket Proxyの設定方法は別記事にする予定です。TCP Routerを使ってPAS上にProxyをデプロイする方法はこちらにメモしました。

解決法の比較

上記の3つは一長一短があります。次の表にまとめます。

👍 👎
Promregator
  • 導入が簡単
  • アプリで設定が不要
  • プログラミング言語に依らない
  • Admin権限がなくても設定可能
  • CAPIへ負荷がかかる
  • パフォーマンスが悪い
  • モニタリング対象追加するにはグループ(Org or Space or App)単位で設定が必要
  • グループ単位でScrape対象のパスが同じである必要がある
  • モニタリング対象追加の毎に再起動が必要
Metric Registrar
  • プログラミング言語に依らない
  • cf CLIのプラグインでアプリ毎にScrape対象のパスを設定可能
  • CF Metric Storeを使えばPrometheus不要
  • CAPIへ負荷がかかる
  • Exporterを別途用意する必要がある
  • Scrape用のエンドポイントに対するアクセスの認証を設定できない
  • PAS 2.4+が必要
  • Platformレベルでの設定が必要
Prometheus RSocket Proxy
  • シンプル
  • (多分)パフォーマンスが良い
  • Admin権限がなくても設定可能
  • Javaのみ利用可能
  • クライアントライブラリが必要(Spring Boot 2.1+)
  • アプリを区別するためのメタデータラベルの追加が必要

Platoformレベルでメトリクスを収集したい場合は、まずはMetric Registrar + Reliability View Exporter for PASを試して見ると良いと思います。新しいバージョンのSpring Bootを使うケースがほとんどの場合はPrometheus RSocket Proxyがフィットするかもしれません。

Platformレベルではサポートされず、Developerレベルでメトリクスを収集したい場合は、PromregatorまたはPrometheus RSocket Proxyを試して見ると良いと思います。

Micrometer用Grafanaダッシュボードサンプル

上記の方法でMicometerのメトリクスをScrapeしている場合は↓のGrafanaダッシュボードを利用できます。

https://github.com/making/demo-micrometer/raw/master/grafana/micrometer-summary-cf.json

image

このダッシュボードは次のラベルが設定されていることを前提に作成されています。

  • org_name
  • space_name
  • app_name
  • cf_instance_id
  • cf_instance_number

が設定されていることが

Promregatorが付与するラベルと互換なので、Promregatorを使っている場合は設定が不要です。 それ以外でSpring Bootを使っている場合はapplication.propertiesに次の値を設定すれば良いです。

management.metrics.tags.org_name=${cloud.application.organization_name:demo}
management.metrics.tags.space_name=${cloud.application.space_name:demo}
management.metrics.tags.app_name=${cloud.application.application_name:demo}
management.metrics.tags.cf_instance_id=${cloud.application.application_id:demo}:${cloud.application.instance_index:0}
management.metrics.tags.cf_instance_number=${cloud.application.instance_index:0}

Java Buildpack 4.21で共通タグが設定されるようになるので、将来的に上記のタグ設定は不要になるでしょう。

https://github.com/cloudfoundry/java-buildpack/issues/644


✒️️ Edit  ⏰ History  🗑 Delete