DatadogのAutoDiscovery機能を使ってPrometheusのエンドポイントを叩いてメトリクスをDatadogに送る

DatadogのAutoDiscovery機能があるのを知ったので試してみたよ、という記事です。 今回は簡単に設定を試すために docker-composeを使って試してみました。

2022/09/29追記: 本記事の内容は少し古くなっています。 本記事では、Prometheusのインテグレーションを使っていますが、OpenMetricsというインテグレーションが別で存在していて この場合、本記事に記載した、extra_headersの設定なしで動くはずです。

はじめに

Spring BootのActuatorエンドポイントには Prometheus向けのフォーマットでメトリクスを公開してくれるエンドポイントがあります。 今回の記事では、Datadog AgentのAutoDiscovery機能を使って MicrometerのPrometheus向けのエンドポイントからメトリクスを取ってDatadogに連携してみる話です。

これは、micrometer-registry-prometheusを依存関係に加えた上で所定のactuatorの設定を追加すると有効になります。 細かい公開される仕様はリファレンスを読んでください。

Spring Boot Reference Documentation

フォーマットとしては以下のような形で公開してくれます。

$ curl localhost:8080/actuator/prometheus
# HELP tomcat_servlet_error_total  
# TYPE tomcat_servlet_error_total counter
tomcat_servlet_error_total{name="default",} 0.0
tomcat_servlet_error_total{name="dispatcherServlet",} 0.0
# HELP tomcat_threads_config_max_threads  
# TYPE tomcat_threads_config_max_threads gauge
tomcat_threads_config_max_threads{name="http-nio-8080",} 200.0
# HELP jvm_threads_states_threads The current number of threads having NEW state
# TYPE jvm_threads_states_threads gauge
jvm_threads_states_threads{state="runnable",} 7.0
jvm_threads_states_threads{state="blocked",} 0.0
jvm_threads_states_threads{state="waiting",} 12.0
jvm_threads_states_threads{state="timed-waiting",} 4.0
jvm_threads_states_threads{state="new",} 0.0
jvm_threads_states_threads{state="terminated",} 0.0
# HELP tomcat_sessions_rejected_sessions_total  
# TYPE tomcat_sessions_rejected_sessions_total counter
tomcat_sessions_rejected_sessions_total 0.0
# HELP system_cpu_count The number of processors available to the Java virtual machine
# TYPE system_cpu_count gauge
system_cpu_count 8.0
# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC
# TYPE jvm_gc_memory_promoted_bytes_total counter

このようなテキストを本来はPrometheusがメトリクスにしてくれるのですが これをDatadog AgentのPrometheus Checkを使って、Datadogにメトリクスとして連携してみます。

Datadog AgentのAutoDiscovery機能とは

Datadog AgentのAutoDiscovery機能とは特定のコンテナにAgentからチェックをする際に コンテナの情報からチェックする内容を判断してくれます。

https://docs.datadoghq.com/ja/containers/kubernetes/integrations/

リファレンスによると、DockerのラベルやKubernetesアノテーションなどからAutoDiscoveryが可能です。

というわけで、今回はローカルで試したいので、docker-composeを使って試します。 また、Discovery方法としてはDockerのラベルという機能を使います。 ドキュメントを見ながら書いてみたのが以下のようなdocker-compose.ymlです。 myappはSpring Bootのアプリケーションです。

version: '3.7'
services:
  myapp:
    image: myapp
    ports:
      - "3001:3001"
    labels:
      com.datadoghq.ad.check_names: '["prometheus"]'
      com.datadoghq.ad.init_configs: '[{}]'
      com.datadoghq.ad.instances: '[{"prometheus_url": "http://%%host%%:3001/actuator/prometheus", "namespace": "local.test","metrics": ["jvm*"]}]'
  datadog:
    links:
     - myapp
    image: datadog/agent:latest
    environment:
     - DD_API_KEY=<REDACTED>
     - DD_TAGS="app:foo-bar-app env:foo-bar-environment"
     - DD_AC_EXCLUDE=".*"
     - DD_AC_INCLUDE="myapp:.*myapp"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc/:/host/proc/:ro
      - /sys/fs/cgroup:/host/sys/fs/cgroup:ro

ちなみに、これは動きません。(2019/12/09現在)

何がダメだったんでしょうか?

ダメだったところは?

以下のリンク先をみてもらうと分かるんですが、Datadog AgentはデフォルトのフォーマットとしてはProtocol Bufferです。 integrations-core/mixins.py at 3653923265d75d13c87b70d2010c06edcf89a8bb · DataDog/integrations-core · GitHub

そのため、Acceptヘッダに Protocol Bufferの類の設定をしていますが Spring BootのActuatorのエンドポイントは text/plain を期待しており、Spring Boot側でマッチするエンドポイントが見つからない、と言ってエラーになります。

Spring Boot側はこんな感じになっていて text/plain; version=0.0.4; charset=utf-8 となっています。

ちなみにProtocol Buffer形式でのメトリクスはPrometheusの2系からサポートしなくなっているようですね。

Exposition formats | Prometheus

じゃあどうすればいいか

Prometheus Checkの設定には extra_headers の設定があります。 extra_headers は datadog agentが prometheusのエンドポイントに対してアクセスする際に付与するヘッダです。 そこで、以下のように Accept ヘッダに text/plain を設定しましょう。 これで動きました。

version: '3.7'
services:
  myapp:
    image: myapp
    ports:
      - "3001:3001"
    labels:
      com.datadoghq.ad.check_names: '["prometheus"]'
      com.datadoghq.ad.init_configs: '[{}]'
      com.datadoghq.ad.instances: '[{"prometheus_url": "http://%%host%%:3001/actuator/prometheus", "extra_headers": {"Accept": "text/plain"}, "namespace": "local.test","metrics": ["jvm*"]}]'
  datadog:
    links:
     - myapp
    image: datadog/agent:latest
    environment:
     - DD_API_KEY=<REDACTED>
     - DD_TAGS="app:foo-bar-app env:foo-bar-environment"
     - DD_AC_EXCLUDE=".*"
     - DD_AC_INCLUDE="myapp:.*myapp"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc/:/host/proc/:ro
      - /sys/fs/cgroup:/host/sys/fs/cgroup:ro

実際にDatadogに送られたメトリクスの様子です。

まとめ

今回は、DatadogのAutoDiscovery機能を使って、Datadog AgentからPrometheus向けにメトリクスを提供するエンドポイントから メトリクスを収集して、Datadogにメトリクスを送る方法を試しました。 一部ハマるところもありましたが、比較的簡単に試すことができました。

Datadog AgentのAutoDiscovery機能は設定をコンテナ側に持たすことができるため、非常に使いやすいです。 ECSのDAEMONでDatadogのAgentを立てた時とかに便利に使えるんじゃないかなと思っています。

今度はECSで試します。

終わり。