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
のようなインスタンス単位で一意なラベルを付与してもちぐはぐなグラフになってしまいます。
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に対して集約されたメトリクスを取得します。
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にメトリクスを保存する方法は後述します。
アプリ毎のメトリクスエンドポイントの定義はドキュメントで説明されているように、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.yml
のserviecs
フィールドに追加しておくのが良いでしょう。
制約としては、Metric Registrar Endpoint Workerに認証情報を渡す方法がなく、エンドポイントに認証を設定することができません。 Workaroundとしては、PrometheusエンドポイントへのアクセスをDoppler VMのIPからのみ許可するように設定することで一般ユーザーにアクセスされることを防げます。
Spring Securityの場合は
hasIpAddress
でホワイトリストの設定が可能です
この制約を許容できない場合は、Structured Log Formatで代替できます。 この場合はPrometheusエンドポイントを用意する代わりに、DogStatsD形式またはJSON形式でメトリクスをログとして標準出力に出力すれば、Firehoseに転送できます。
Micrometerを使っている場合はStatsD RegistryのDatadog Flavorを使用し、
lineSink
メソッドで標準出力にメトリクスを出力すれば良いです。
Firehoseに送られたメトリクスをPrometheusに保存するにはExporterが必要です。Firehose -> PrometheusのExporterとしては次の2つがあります。
- Firehose Exporeter(OSS): https://github.com/bosh-prometheus/firehose_exporter
- Reliability View Exporter for PAS: https://docs.pivotal.io/reliability-view
PASを使う場合はReliability View Exporter for PASを使えば良いと思います。
Firehose Exporeterはメトリクス名にPrefixが付くため、Grafana Dashboardが作りにくいです。
PrometheusのScrape ConfigにはこのExporterの設定を行えば良いです。次の図のような構成になります。
Firehoseに送らられたメトリクスはPrometheus CompatibleなMetric Storeに長期間保存することができます。
Metric Storeはこちら。
- OSS版: https://github.com/cloudfoundry/metric-store-release
- Enterprise版: https://docs.pivotal.io/metric-store
OSS版はSingle NodeでEnterprise版はMulti Nodes/HAに対応しています。
この場合はGrafanaからPrometheusデータソースとして直接Metric Storeを登録可能です。
Metric StoreはUAAと連携して、Developerがデプロイしたアプリのメトリクスのみ取得できるように認可制御させることもできます。 Grafanaの設定方法はこちらを参照してください。
Metrics Registrarはデフォルトで、
deployment
、job
、index
、id
タグ(Prometheusのラベル)を取り除いてFirehoseに送ります。
Micrometerを使っている場合はid
タグはメトリクスを区別するのに重要な情報なので、Blacklisted Tagsからid
を除外してください。
Prometheus RSocket Proxy
最も新しい解決方法がPrometheus RSocket Proxyです。
RSocketプロトコルを使用して、アプリとPrometheus Proxyが双方向に通信します。 PromethesuはPrometheus RSocket Proxyに対して集約されたメトリクスを取得します。
Promregatorと少し似ていますが、Promregatorとは異なり、Prometheus RSocket ProxyからアプリへのアクセスはLoad BalancerやGoRouterや経由せず直接通信になります。
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 |
|
|
Metric Registrar |
|
|
Prometheus RSocket Proxy |
|
|
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
このダッシュボードは次のラベルが設定されていることを前提に作成されています。
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で共通タグが設定されるようになるので、将来的に上記のタグ設定は不要になるでしょう。