OpenTelemetry CollectorでPrometheus Remote Storageへ直接メトリクスを書き込む


OpenTelemetryとは

画像引用元: https://www.appdynamics.com/blog/product/what-is-opentelemetry/

OpenTelemetryOpenTracingOpenCensusがマージされできたプロジェクトでこれら二つの次のメジャーバージョンとして提供されます。
トレース、メトリクス、ログのようなテレメトリーデータの作成・管理をするためにデザインされたAPI・SDK・ツールのセットを提供され、OpenTelemetryを利用することでテレメトリデータを計測・生成・収集・エクスポートができるようになります。これ自体はストレージやビュー等を提供するものではないため、トレーシングであればJaegerやZipkin、メトリクスであればPrometheusなどオープンソースまたはクラウドプロバイダにより提供されている商用のバックエンドに対してテレメトリデータをエクスポートすることになります。

OpenTelemetryを用いてアプリケーションからテレメトリデータを収集する場合、言語毎に実装されたAPI・SDKを用いて直接インストルメンテーションしたり、Prometheusのexporterのようにアプリケーションの外部からテレメトリデータを収集し、直接バックエンドに対してエクスポートするかまたは後述のOpenTelemetry Collectorに対してテレメトリデータをエクスポートすることになるかと思います。

現在(2020/11/25時点)で多くのコンポーネントがすでにbetaの状態でGAに向けて作業中のようです。ログに関しては初期の段階ではサポートしていませんが、後ほど組み込むことを目指しているようです。

OpenTelemetry Collector

OpenTelemetry CollectorはOpenCensusのOpenCensus Serviceのような構成を一つのコンポーネントで実現できるものとして理解しています。OpenTelemetry CollectorはOpenTelemetryで提供されているものの一つでこれ自体が単体のアプリケーションとして起動するものであり、テレメトリデータを受信・処理・エクスポートする方法をベンダーに依存しない実装で提供します。

OpenTelemetry Collectorではレシーバーで実装され対応しているフォーマットのテレメトリデータ(PrometheusやJaegerなど)を受け取り、エクスポーターで実装されているバックエンドに対してテレメトリデータをエクスポートするためのものです。

受信したテレメトリデータのためのバッチ処理、リトライ、フィルター、加工などが可能であり、アプリケーション側からこれらの処理をCollectorへオフロードできます。


画像引用元: https://kccncna20.sched.com/event/eoEq

また複数のバックエンドに出力することが可能で、これにより様々なバックエンドのためのエージェント・コレクターをOpenTelemetry Collectorへまとめることが可能です。OpenTelemetryで提供されている特定の言語向けSDKでは実装されておらずエクスポートできないモニタリングサービスバックエンドがあった場合でも、Collector側のエクスポーターで実装されていればCollectorを介してエクスポートできます。OpenTelemetry Collectorから別のOpenTelemetry Collectorへエクスポートも可能であり、アプリケーションの近く(例えばPodのサイドカーや同じノード上)に起動して、さらに別のCollectorで集約するといった構成も可能です。


画像引用元: https://kccncna20.sched.com/event/eoEq

OpenTelemetry Collectorとしては以下の2種類のものが公開されています。

  • opentelemetry-collector
    • コアリポジトリであり主要な機能とメジャーなオープンソースのレシーバーとエクスポーターを含むもの
  • opentelemetry-collector-contrib
    • opentelemetry-collectorのスーパーセットであり主要な機能でないものや、その他のオープンソースや商用のバックエンドのための実装を含むもの

Collectorは自作することも可能のようで、社内に独自のモニタリングサービスがありそれらに対応したCollectorのディストリビューションを開発したい場合には以下が参考になるかもしれません。私も時間を見つけて遊んでみようと思います。

OpenTelemetry Collectorを試す

OpenTelemetry Collectorを利用してKubernetes上に稼働しているアプリケーションが出力するPrometheus形式で出力されたメトリクスを収集し、直接PrometheusのRemote Storageへエクスポートしてみました。OpenTelemetry Collector、Thanos、アプリケーションは全て同じKubernetesクラスタ上で動かします。
Prometheus形式のメトリクスの取得と、PrometheusのRemote Storageへの書き込みはopentelemetry-collectorに含まれているため、今回はこちらのCollectorを利用します。

Remote StorageにはThanosを利用しました。ThanosはReceiverというコンポーネントを利用することでPrometheusのRemote Writeのリクエストを受け付けることができます。
Thanos自体はRemote ReadのAPIは利用できませんが、PrometheusのAPIを直接話すことができるQueryというコンポーネントがあるため、PrometheusがなくともGrafanaからThanosへ保存されたデータを参照することができます。つまりOpenTelemetry CollectorとThanosによりPrometheusが存在しない構成がとれます。

バージョン情報

  • OpenTelemetry Collector v0.15.0
  • Thanos v0.17.0
  • Kubernetes v1.19.4

OpenTelemetry Collectorの設定

OpenTelemetry Collectorに必要な設定は大きく以下の三つです。

  • exporters
    • テレメトリデータのエクポートに関する設定
  • processors
    • テレメトリデータの加工、フィルター、リトライ、バッチ処理等の設定
  • receivers:
    • どういうフォーマットでどのようにテレメトリデータを受信するかという設定

どのような設定が全体として必要かは公式ドキュメントをご参照ください。
ここでは今回利用した設定・マニフェスト等はこちらです。この中からOpenTelemetry Collectorの設定でexportersとreceiversに関連する部分だけ少しピックアップします。

exporters

今回はPrometheusのRemote Writeへ出力します。今回はTLSを利用しているわけではないため、PrometheusのRemote Writeに関する設定はシンプルに以下だけです。

exporters:
  prometheusremotewrite:
    endpoint: "http://thanos-receive:19291/api/v1/receive"

設定可能な全ての項目はこちらをご参照ください。

receivers

Prometheus形式のメトリクスを取得する設定にはPrometheusのconfigと同じコンフィグのフォーマットが利用できるようです。
そのためscrape_configが利用可能であり、スクレイプ対象のターゲットやリラレベルに関する設定にPrometheusの設定をそのまま利用できるのは嬉しいですね。
今回はPrometheusのgithubリポジトリで管理されているこちらの設定ファイルをベースとして利用しています。

receivers:
  prometheus:
    config:
      global:
        scrape_interval: 1m
        scrape_timeout: 30s
      scrape_configs:
        ...(省略)

設定可能な項目はこちらをご参照ください。

Prometheusと同様にターゲットのディスカバリにはKubernetesのAPIを利用します。そのためRBACを有効にしている場合は、OpenTelemetry Collectorに対して適切なロールの割り当てが必要です。現在利用しているPrometheusと同じClusterRole, RoleをCollectorが利用するサービスアカウントに対して割り当てれば十分なはずです。例えばこのようなClusterRoleのようなものが利用できます。

実際に動かす

Kubernetesクラスタが用意できる方は以下のコマンドで試すことができます。

$ kubectl apply -f https://gist.githubusercontent.com/uesyn/a7ec18c98b6e5ae822f8433c2d4aea2a/raw/58b8682113c725ce6b5884f81ecff19d2f40f00f/demo-otel-collector-and-thanos.yaml

上記でThanosとOpenTelemetry Collectorがデプロイされます。
メトリクスを出力するサンプルアプリもデプロイします。

$ kubectl apply -f https://gist.githubusercontent.com/uesyn/f9d8c352d4f57f857be9abd09a136706/raw/5d4d56c379785aa0d0bf7e5b2afcbe13c61046ff/random-metrics.yaml

下記のコマンドでThanosのUIへport-forwardし、上記のアプリケーションのメトリクスを確認すると、メトリクスが収集されていることが確認できます。

$ kubectl -n otel port-forward svc/thanos-query 10902:10902

最後に

上記以外のアプリケーションのメトリクスを収集していて気づいたのですが、
同様の設定のPrometheusと比べた場合に、いくつかの種類のメトリクスが現状exportされません。
またいくつかのターゲットが漏れていることがわかりました。前者については現状のexporterの制約のように見えますが、後者については軽く確認した限りメトリクスを収集するポートやパスをrelabelにより変更した場合にうまく取得できていないようです。同じ設定でPrometheusを動かした場合は正常に動作したため、receiverのバグだと思うのですが引き続き調べてみようと思います。
個人的に気になっているプロジェクトなので今後も動向を追っていこうと思います!
またメトリクスに関して言えばVictriaMetricsのvmagentで今回と似たようなことができそうなため、こちらも試していきたいです!

参考