cAdvisorのメトリクスなどに存在するラベル「id」の正体

# はじめに
この記事では，僕がアラートルールの設定中に遭遇したidというラベルの正体について書いています．既に知っている方には新しい情報は少ないと思います．なにそれ！？と思った方や，僕と同じように困っていた方には，役立つかなと思います．

# 経緯
まず，僕がこのidという存在に困った話をします．
僕は研究室の監視環境を整えるうえで，Kubernetes環境のpodの監視ルールの設定を任されていました．
cAdvisorというコンテナ監視用のexporterを使用して，Prometheusにメトリクスを収集していました．そしてその収集したメトリクスを用いて，PromQLクエリ式でルールを設定していました．
ここで，コンテナ（pod）のメモリ使用率のアラートルールを設定しようとしたところ，次のようなメトリクスの値が取れました
```
container_memory_usage_bytes{beta_kubernetes_io_arch="amd64", beta_kubernetes_io_instance_type="k3s", beta_kubernetes_io_os="linux", id="/", instance="master", job="kubernetes-nodes", kubernetes_io_arch="amd64", kubernetes_io_hostname="master", kubernetes_io_os="linux", node_kubernetes_io_instance_type="k3s", node_role_kubernetes_io_control_plane="true", node_role_kubernetes_io_master="true"}
```
これの何が問題なんだと思う方もいると思います．
ここで重要なのは，僕は**podのメモリ使用率**を取得しようとしているということです．
本来ほしいのは以下のようなメトリクスの値でした
```
container_memory_usage_bytes{beta_kubernetes_io_arch="amd64", beta_kubernetes_io_instance_type="k3s", beta_kubernetes_io_os="linux", container="alertmanager", id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod6a69032e_6c67_424a_abb6_7f374ef886fe.slice/cri-containerd-59516de8ffbb81b5e3ac6bece07e8f8800d661d2cb08f9fe1bbbe47e2d234250.scope", image="docker.io/prom/alertmanager:latest", instance="core-s4", job="kubernetes-nodes", kubernetes_io_arch="amd64", kubernetes_io_hostname="core-s4", kubernetes_io_os="linux", name="59516de8ffbb81b5e3ac6bece07e8f8800d661d2cb08f9fe1bbbe47e2d234250", namespace="alert", node_kubernetes_io_instance_type="k3s", node_role_kubernetes_io_control_plane="true", node_role_kubernetes_io_etcd="true", node_role_kubernetes_io_master="true", pod="alertmanager-9b5997c44-2s2hr"}
```
何がいいのかというと，よく見てみるとこっちはpodというラベルやnamespaceというラベルがあります．そのため，どこのnamespaceにあるどのpodなのか特定できます．

一方で一つ目の値だとどうでしょうか．
よく見てみてもpodやnamespaceというラベルが存在しません．
これだとpodの監視ができないじゃないか！

そこでこのメトリクスにある情報を色々見ていたところ，idというものを見つけました．
```label:一つ目のメトリクスの値にあったid
id="/"
```
```label:二つ目のメトリクスの値にあったid
id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod6a69032e_6c67_424a_abb6_7f374ef886fe.slice/cri-containerd-59516de8ffbb81b5e3ac6bece07e8f8800d661d2cb08f9fe1bbbe47e2d234250.scope"
```

なんか階層構造みたいになってそうです．
他にもみていたところ，こういうのもありました．
```label:別のid
id="/system.slice/k3s.service"
```
これはk3sのことをいってそうですね．ちなみにpodやnamespaceのラベルはありませんでした．

ここまでで分かったこと
* idが階層構造になっていそうということ
* idの内容によってpodのものとシステム側のものが分かれていそうということ

これだけだとよく分からないためもっと色々調べてみました．

# idの正体
調べた結果，idの値にかなり類似したものを見つけました．
**cgroups**というものでした！
cgroupsについては以下のURLで説明されています．
https://valinux.hatenablog.com/entry/20210114

このサイトによると，podやコンテナはKubernetesによってコントローラごとに階層構造で作成しているらしく，それがどんな構造化というと，
> ```
> /kubepods
>    /<Guaranteed Pod の UID>
>         /<コンテナID>
>     /burstable
>         /<Burstable Pod の UID>
>             /<コンテナID>
>     /besteffort
>         /<BestEffort Pod の UID>
>             /<コンテナID>
> ```
というような構造になっているみたいです！
僕が取得した二つ目のメトリクスの値にあったidと比べると，
```
/kubepods.slice/kubepods-besteffort.slice/
```
このように，それらしき階層構造になっています．

そもそもcgroupとは何なんでしょう．このサイトによると，
> cgroup とは、Linux カーネルの機能の1つであり、プロセスやスレッドが利用するリソースの制限や分離を行うための機能です。 cgroup は名前空間の機能と共に、Linux コンテナの根幹を成す技術の1つでもあります

だそうです．

つまりcgroupによって，kubernetesのpodやコンテナのみならず，ノード全体のリソースの切り分けを行っているみたいです．

# 結局何がどういうことだったのか
それでは僕が経験した問題について考察してみます．
```
id="/"
```
これはkubepodsよりも上位の階層ということになります．つまり，podやk3sのserviceのようなシステムのメモリ使用率も合わせたノード全体を指すのではないでしょうか？
だから，podもnamespaceも無いんじゃないでしょうか？

逆に，以下のidを見てみます
```
id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod6a69032e_6c67_424a_abb6_7f374ef886fe.slice/cri-containerd-59516de8ffbb81b5e3ac6bece07e8f8800d661d2cb08f9fe1bbbe47e2d234250.scope"
```
これは，kubepods以下の，QOSクラスがbesteffortのpodの，criのコンテナという感じですかね．
ここまでidで表されていれば，podであると判断できるでしょう．

# 結論
idの正体はcgroupによるpodの階層構造でした．
また，cAdvisorが取得したメトリクスには，podだけではなく，ノード自体やk3sサービスのものも含まれていた．そのため，namespaceやpod名が取得できないメトリクスも存在していた．

この情報がお役に立てたなら幸いです．