実測データで読む cAdvisor と node exporter
目標
このサイトを動かしている7ノードのクラスターから取得した実測メトリクスで、cAdvisorとnode exporterの数字を読みます。終わると、コンテナのCPU・メモリ・throttleのメトリクスを見て、「これは多いのか」に、根拠を持って答えられるようになります。
なぜ重要なのか
PromQLの文法をすべて知っていても、メトリクスが何を数えたものかを知らなければ、数字を解釈できません。累積カウンターの大きさは、長く生きているコンテナが常に勝ち、working setとusageは別のものを数え、CPUの上限は、cAdvisorではなくkube-state-metricsが教えてくれます。この3つを知らないと、ダッシュボードはきれいでも、判定は毎回間違います。ここで扱うデータは、実際のクラスターのものなので、値がきれいではありません。throttleは0.19%で、上限のないコンテナには、メトリクスがまったくありません。現場とはそういうものです。
データについて
- ウィンドウは固定された3時間です。
lab-realdataで確認してください。 - クエリは、
promq-at "<PromQL>"で投げます。このヘルパーが、ウィンドウ内の固定された時刻で問い合わせます。そのままpromqを使うと、今の時刻なので、結果が空になります。 - エクスポーターの公開形式の原文は、
/opt/lab/realdata/expo/にあります。 - 出典・採取時刻・手を加えた内容は、
/opt/lab/realdata/README.mdに書かれています。内部IPとホスト名は消していません。このサイトの実際のクラスターです。
ステップ
lab-realdataでウィンドウを確認し、monitoringネームスペースでcontainer_cpu_usage_seconds_totalを出力しているPodが何個かを数えるクエリを、/root/pca-exporters/01-count.promqlに書きます(時系列の数ではなく、Podの数です)。monitoringのprometheusコンテナが、今何コア使っているかを出すクエリを、/root/pca-exporters/02-cpu-rate.promqlに書きます。- CFS throttleの比率(
throttled_periods / periods、ウィンドウは[1h])の最大値を出すクエリを/root/pca-exporters/03-throttle.promqlに、その比率が最も高いコンテナの名前を、/root/pca-exporters/03-throttle.txtに1行で書きます。 monitoringのgrafanaコンテナで、container_memory_usage_bytesとcontainer_memory_working_set_bytesの差を出すクエリを/root/pca-exporters/04-inactive.promqlに、その差と同じ値を出すメトリクスの名前を、/root/pca-exporters/04-inactive.txtに書きます。aiネームスペースのttsコンテナのQoSクラスを、idラベルから読んで、/root/pca-exporters/05-qos.txtに1行で書きます。/opt/lab/realdata/expo/cadvisor-nuc1.txtにはあるのに、Prometheusにはないメトリクスの名前を、3つ以上見つけて、/root/pca-exporters/06-dropped.txtに1行に1つずつ書きます。aiネームスペースで、CPUの上限に対する使用率が最も高い値を出すクエリを、/root/pca-exporters/07-limit-join.promqlに書きます。192.168.219.120:9100ノードのCPU使用率(0–1)を出すクエリを、/root/pca-exporters/08-node-cpu.promqlに書きます。- 同じノードの
MemAvailableとMemFreeの差を出すクエリを、/root/pca-exporters/09-mem-available.promqlに書きます。
参考
promq-at "count(up)"のように、引用符の中にクエリを入れます。ファイルに書いたクエリは、promq-at "$(cat <파일>)"(プレースホルダーはファイル名です)で投げてみてください。- よくあるミス1: 結果が空なら、クエリではなく時刻を疑ってください。
promqは今の時刻で問い合わせ、実測データは過去の固定されたウィンドウにだけあります。 - よくあるミス2: ラベルの集合が異なる2つのメトリクスを、そのまま割ったり引いたりすると、結果が空になります。
on(...)で合わせるか、同じラベルに絞ってください。
読み込まれた実測データを確認してPodの数を数える
lab-realdataが、問い合わせられる時刻のウィンドウを教えてくれます。クエリはpromq-atで投げてください。今の時刻で投げると、ウィンドウの外なので、空の結果が返ります。count()をそのまま使うと、時系列の数、つまりコンテナの数が出ます。Pod1つに複数のコンテナがありうるので、podで先にまとめてから数えて、はじめてPodの数になります。
累積カウンターの傾きを測る
container_cpu_usage_seconds_totalは、生まれてから使ったCPU秒を足し続けた値です。今何コア使っているかは、rateで傾きを測ると出ます。ウィンドウ内であれば、[5m]から[30m]のどれでもかまいません。ネームスペース全体ではなく、prometheusコンテナ1つに絞ってください。
throttleの比率で上限の超過を判定する
throttled_periodsは個数なので、その値だけでは深刻かどうかわかりません。同じウィンドウのperiodsで割って、比率を出してください。最も高いコンテナは、topk(1, ...)で探し、結果のcontainerラベルを読みます。上限のないコンテナには、このメトリクスがまったくありません。
usageとworking setの差が何なのかを確認する
2つのメトリクスを、同じラベルに絞って引けばよいです。ラベルの集合が違うと、引き算の結果が空になってしまいます。その差とまったく同じ値を出すメトリクスが別にあります。promq-atで、grafanaコンテナのcontainer_memory_で始まるメトリクスを一通り見てみてください。
cgroupのパスからQoSクラスを読む
container_cpu_usage_seconds_totalのidラベルが、cgroupのパスそのものです。kubepods-besteffort・kubepods-burstableの節を探してください。GuaranteedのPodは、その節がまったくありません。aiネームスペースのttsコンテナを見ればよいです。
原文にはあるのにPrometheusにはないメトリクスを探す
/opt/lab/realdata/expo/cadvisor-nuc1.txtが、kubeletが実際に出力した原文です。そこにあるメトリクスの名前を、promq-atで1つずつ投げてみてください。結果が空になるものが、スタックのmetric_relabelが捨てたメトリクスです。3つ以上見つけて書いてください。
kube-state-metricsとつなげて、上限に対する使用率を出す
上限はcAdvisor側にないので、kube_pod_container_resource_limitsから取得します。2つのメトリクスはラベルの集合が違うので、そのまま割ると結果が空になります。両側をsum by (pod,container)で、同じラベルまで減らすか、on(pod,container)で合わせてください。resource="cpu"で絞ることを忘れないでください。メモリの上限まで混ざると、値が無意味になります。
モードごとの累積時間から、ノードのCPU使用率を出す
node_cpu_seconds_totalは、コア1つ×モード1つごとに時系列が1つです。idleモードのrateをコア数で平均して、1から引くと、0–1の使用率になります。sumを使うと、コア数の分だけ大きくなります。ノードは192.168.219.120:9100です。
MemFreeとMemAvailableの差を測る
2つのメトリクスを、同じinstanceに絞って引けばよいです。この差が、「今はキャッシュが使っているが、必要なら渡せるメモリ」です。ノードは、前のステップと同じ192.168.219.120:9100です。