k8s上でRustで作ったgRPCサービスのメトリクスを可視化する
この記事はRust Advent Calendar 2021 6日目の記事です。
はじめに
実用的なサービス開発、運用する上でメトリクス計測・可視化は必要不可欠なものとなっています。Rust言語でそのような記事や具体的なサンプルがなかったので、やり方を解説してみます。
やりたいこと
- Rustで超シンプルなgRPCアプリケーションを作る
- metrics-rsを使ってgRPCアプリケーションのメトリクスを記録する
- 作ったアプリケーションをKubernetes上で動かす
- Prometheusでアプリケーションのメトリクス用のエンドポイントをService DiscoveryしてGrafanaで可視化する
RustでgRPCアプリケーションを作る
RustでgRPCを使う選択肢はいくつかあります[1]。今回はtonicを使ってみたいと思います。tonicを使う利点として、protobuf/grpcのコードを別々にビルドする必要がなく、cargo build
の中で自動的に生成してくれるところにあります。
今回はこのようなプロトコルを使います。
syntax = "proto3";
package foo;
service Foo {
rpc echo(EchoRequest) returns (EchoReply);
}
message EchoRequest {
string name = 1;
}
message EchoReply {
string message = 1;
}
Client,Serverの実装はここを見てください。
metrics-rs
とは?
metricsはRust言語でメトリクスを記録したり、Prometheus用のアダプタを簡単に作ることができるcrateです。
metrics
プロジェクトには以下のcrateがあります。今回はmetrics
とmetrics-exporter-prometheus
を使います。
- metrics: メトリクス記録のためのtraitやマクロを提供する。logクレートみたいな存在。
- metrics-tracing-context: tracing[2]との連携
- metrics-util: metrics内部で使われるライブラリ
- metrics-macros: metrics内部で使われるライブラリ
- metrics-exporter-tcp: TCP用のexporter
- metrics-exporter-prometheus: Prometheus互換のexporter
metrics-rs
でメトリクスを記録する
metrics
は以下の3つのメトリクスをサポートしています。
- Histgram
histogram!("some_metric_name", 34.3);
- Gauge
gauge!("some_metric_name", 42.2222);
- Counter
counter!("some_metric_name", 12);
また、全てのメトリクスのタイプに共通して、任意のkey/valueを追加することができます。ここで追加したkey/valueはGrafana側で可視化するためのクエリで使うことができます。
histogram!("some_metric_name", 34.3, "key" => "value");
今回はServer側のecho
APIのハンドラ内で以下のメトリクスを記録しています。コードの詳細はこちら
// "echo" APIのレイテンシーの計測
histogram!("foo_histgram", now.elapsed(), "api" => "echo", "result" => "ok");
// とりあえず増えていくだけのカウンター
increment_counter!("foo_counter");
// とりあえず増えていくだけのゲージ
increment_gauge!("foo_gauge", 10.0);
Prometheus互換のexporterを立てる
metrics-exporter-prometheusを使うと、たった一行でPrometheus互換のexporterを簡単に立てることができます。
metrics_exporter_prometheus::PrometheusBuilder::new().install()?;
この一行でプログラムの中で小さいhttpサーバーが起動し、JSONでメトリクスを返すことができます。
git clone git@github.com:yukinarit/rust-k8s-grpc-metrics-example.git
cd rust-k8s-grpc-metrics-example/server
cargo run
server
を実行すると、0.0.0.0:9000
をLISTENしたhttpサーバーが立ち上がりました。
$ netstat -an | grep LISTEN | grep 9000
tcp4 0 0 *.9000 *.* LISTEN
このエンドポイントに対してcurlするとメトリクスのスナップショットを表示できます。
$ curl http://localhost:9000/
# TYPE foo_counter counter
foo_counter 120
# TYPE foo_gauge gauge
foo_gauge 1200
# TYPE foo_histgram summary
foo_histgram{api="echo",result="ok",quantile="0"} 0.000011611
foo_histgram{api="echo",result="ok",quantile="0.5"} 0.00003000039410022207
foo_histgram{api="echo",result="ok",quantile="0.9"} 0.00005798651714158709
foo_histgram{api="echo",result="ok",quantile="0.95"} 0.00007568731078309839
foo_histgram{api="echo",result="ok",quantile="0.99"} 0.0001138418862207591
foo_histgram{api="echo",result="ok",quantile="0.999"} 0.0001233727823801684
foo_histgram{api="echo",result="ok",quantile="1"} 0.00048648716917468264
foo_histgram_sum{api="echo",result="ok"} 0.005295823000000002
foo_histgram_count{api="echo",result="ok"} 120
gRPCアプリケーションをKubernetes上で動かす
cd rust-k8s-grpc-metrics-example
-
server.yml
: Deploymentでserver
をデプロイする -
client.yml
: CronJobでserver
に対して1秒に一回"echo" APIをcallする -
prometheus.yml
: Prometheusをデプロイする -
grafana.yml
: Grafanaをデプロイする
Prometheusでメトリクスを収集する
Prometheusにはkubernetes_sd_config[3]というKubernetes上のサービスをService Discoveryする機能があります。今回作ったserver-metrics-service
サービスを追加するためのyamlは以下のようになります。
- job_name: kubernetes-service
scheme: http
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
regex: default;kubernetes
action: drop
- source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
regex: default;server-metrics-service;metrics
action: keep
Grafanaでメトリクスを可視化する
Grafanaで自分で記録したfoo_histgram
, foo_counter
, foo_gauge
メトリクスを使って以下のダッシュボードを作ることができました。ダッシュボードの設定の詳細は知りたい人は、dashboard.jsonを使ってみてください。
おわりに
アドベントカレンダーに間に合わせるために説明がかなり雑になってしまいましたw
この記事作成に使ったコードは全て以下のリポジトリにあるので、興味がある人は参照してみてください。
Discussion