たんぶろぐ

すぐ忘れる

Datadog を Kubernetes 上で運用するときのカーディナリティ設定

先月あたりからこんな事象に悩まされていた。

f:id:ZuiUrs:20200707192926p:plain
before

この画像は、Kubernetes 上の Deployment に対して一定の負荷 (50 req/s) をかけながら、レプリカ数を変化させたときのグラフである。

Deployment がどのくらいの負荷を受けているのかを見たかったのだが、グラフ化したときに意図した通りにならずモヤモヤしていた。この実験は一定負荷なのでレプリカ数を変えても Deployment 全体で受けている負荷は変わらないはず。それなのにレプリカ数を増やすとなぜか負荷が減っているように表示されてしまう。どうして。

TL;DR

Datadog Agent の環境変数 DD_CHECKS_TAG_CARDINALITYorchestrator を設定すれば解決する。

続き

これを最初見たとき、Aggregator 設定をミスっているのかと疑ったが、ちゃんと sum を指定していた。グラフを作るときはタグでメトリクスを絞ると思うが、これによってヒットしたメトリクスの合計値が表示されるようになる。ちなみに avg を指定していると平均値となってしまうため、レプリカ数が増えるに従って値は減少していく。

次に Rollup 設定を疑った。結局これは関係なかったのだが一応自分のために書いておくと、Rollup はデータポイントを減らす目的で適用されるメトリクスのまとめ方式の仕組みなので関係ない (デフォルトの avg で問題ない)。Datadog が送ってくれるデータポイントは最大 350 個なので、実際は大量にあるデータポイントがこの設定によって 350 個以下に圧縮される。そのときの計算方式の設定である。これにより長期間のメトリクスを Datadog Dashboard や Query API で取得した際にデータ量が爆発することを防いでいる。わかりやすくいうと Rollup は時間 (ヨコ方向) のまとめ方式であり、Aggregator は各ホストのメトリクス (タテ方向) のまとめ方式である。

ここらへんでサポートに聞いてみることにした。このときはまだ今ほど理解がクリアになっていなかったので話が何度か食い違ったが、どうやらカーディナリティの設定を上げる必要があるらしい。

カーディナリティを上げるとメトリクスのタグ情報が増える。これは Datadog Agent の環境変数 DD_CHECKS_TAG_CARDINALITY を介して設定することができ、低い方から low, orchestrator, high が値としてある。デフォルトは low であり、この場合はホストのタグ情報と Kubernetes Integration のタグしか付与されない。これを orchestrator にすることで pod_name というタグが付くようになる。high にするとさらに下層の Docker コンテナの名前や ID なども付与されるが、そこまで必要になることはあまりないだろう。ちなみにこれは公式の Kubernetes Installation マニュアルに載っていないので注意が必要である。

では最後になぜカーディナリティの設定が必要なのかについてまとめる。これはメトリクスの扱いの仕様が関係している。Datadog だとタグでメトリクスの一意性を判断しているため、同一のタグを持つメトリクスは同じものと認識される。例えばノード数 3 のクラスタ上にレプリカ数 6 の Deployment があったとする。このときカーディナリティが low だと、メトリクスはホストレベルでしか一意識別性を持たないため 3 種類として認識される (6 つのメトリクスは送られているが、おそらく同一ホスト上のコンテナは同じメトリクスと判断されて 1 つを残して他は無視される)。つまり sum Aggregator を使っても 3 つのメトリクスしか合計されない。これにより、レプリカ数が増えると本来一定のはずの合計値メトリクスが減っているように見えてしまう。

その後、カーディナリティの設定をして同一の実験を試してみた。意図したとおりに表示されている。良かった。

f:id:ZuiUrs:20200707193014p:plain
after

おまけ

Kubernetes クラスタの一意識別性について。

自分の職場は毎日数個の Kubernetes クラスタが作られは消されるような環境なので、Datadog に登録されているクラスタもなかなか多い。そこでメトリクスを絞り込む際に、他のクラスタの情報が混ざらないように一意識別するためのタグを探していた。

調べてみると Kubernetes 自体はクラスタの ID 情報は持たないが、その代わりとして kube-system Namespace の UID が使えるらしいということがわかった。とりあえず今はこれで満足している。