helmでDatadogを入れることが多いんだけど,これで立ち上がるDogStatsDにアプリケーションからカスタムメトリクスを送りたいことがある.
https://github.com/helm/charts/tree/73e2adc5d2250d02cb02ef4602b7eeda05e6aaf4/stable/datadog
現状のdatadogのchartでは,datadog/dogstatsd
のdocker imageを立ち上げている場所はないが,datadog/agent
は各所で起動してくれる.agentはdogstatsdを内包しているので,agentであっても,dogstatsd用のUDPポートがあいていればdogstatsdとして利用可能だ.
このchart内の
このtemplateでは, DD_DOGSTATSD_PORT
が設定されており,dogstatsdが利用できる.このcluster-agent.yaml
は
https://github.com/helm/charts/blob/73e2adc5d2/stable/datadog/templates/daemonset.yaml#L63
ここで参照されているため,daemonsetで起動するDatadogのプロセスはdogstatsdとして利用可能だ.
つまり,DaemonSetで起動したDatadogのPodに,アプリケーションからUDPでメトリクスを送りつけることができれば良い.
任意のアプリケーションPodからDaemonSetにアクセスする
ここに書かれているような方法がある.HeadlessServiceを作ったり,Serviceを作ってアクセスするという手もある.ただ,よく考えると基本的にDaemonSetはすべてのNodeに配置されているはずである. となると,Serviceで無駄にLBを経由して,その結果どのPodにアクセスがいくかはわからないという構成は,そんなにスマートとは思えない(楽だけど).
すべてのNodeにDaemonSetのPodが配置されるのであれば,当然アプリケーションを実行しているPodが存在するNodeにもDaemonSetのPodは存在する.そこにアクセスできれば一番スマートな気がする.
ホストのIPでDaemonSetへのアクセスを受け付ける
これをやるには, spec.template.spec.hostNetwork: true
にすれば良い.
他には,ports
の設定時にhostPort: 8125
(これはdogstatsdのポート)とかしても良い.ただし他のコンテナのポートと被らないようにする必要はあるが.
前述のhelm chartを使うのであれば,
releases: - name: datadog namespace: kube-system chart: stable/datadog values: - agents: useHostNetwork: true - datadog: apiKey: hogehoge appKey: fugafuga dogstatsd: nonLocalTraffic: true
みたいな helmfile.yaml
にしとけばいい.
一つ重要なこととして,nonLocalTraffic: true
にしておかないと,外から投げられたカスタムメトリクスをdatadogに送ってくれない.
自身のホストIPに向かってリクエストを投げる
次はアプリケーションのPod側の話.DogStatsDはホストIP+8125ポートで待ち受けてくれているので,ここにUDPリクエストを投げれば良い.
ホストのIPを知るためにはDownward APIを使う.使えるものはこのへんに書いてあるが,とりあえずホストのIPを知りたければ status.hostIP
で取れる.
つまり,アプリケーションのPod定義内で
containers: - name: application image: ruby:2.7.1 env: - name: DD_AGENT_HOST valueFrom: fieldRef: fieldPath: status.hostIP
としておけば, DD_AGENT_HOST
でホストのIPが取れる.内部ではdogstatsdのライブラリを使って,
require 'datadog/statsd' statsd = Datadog::Statsd.new(ENV['DD_AGENT_HOST'], 8125)
とかしておけば使える.
参考
ほぼこれと同じことを説明している.
ただ,最近のdatadog/agent:7
あたりだと,hostNetwork: true
であっても hostPort: 8125
であっても,どちらでも正しくインスタンスのホスト名が取得されており,hostname=Pod名とはならなかった.なので hostNetwork
でもhostPort
でもどちらでも良いと思う.