KubernetesのネットワークオブザーバビリティプラットフォームRetinaを試してみた＜中編：メトリクス使いこなし編＞

<!-- KubernetesのネットワークオブザーバビリティプラットフォームRetinaを試してみた＜中編：メトリクス使いこなし編＞ -->
# はじめに
三菱電機のノザワです。

本記事は、KubernetesクラスターのネットワークオブザーバビリティプラットフォームであるRetinaについてまとめた記事の中編です。
メトリクスに関してRetinaの各機能を具体的に触ってみた内容を取り上げます。
当初は前編と後編を想定していましたが、長くなってしまったため、キャプチャは次回の後編で取り上げることにします。

Retinaとは何か調査した内容や手元のオンプレKubernetesクラスター上で環境構築した内容は前編にまとめていますので、あわせてお読みください。

https://qiita.com/melknzw/items/a8986b12fa124a2d5df0


__本記事で触れる内容__
* Retinaが収集するメトリクス
* Retinaにおけるメトリクスの収集設定方法

__本記事で触れない内容__
* Kubernetesの基礎知識
* `kubectl`や`helm`コマンドの使い方


# Retinaとは(おさらい)
今回取り上げるRetinaは、Microsoft社が2024年3月19日にOSSとして公開したKubernetesクラスターのネットワークオブザーバビリティツールです。

https://retina.sh/

執筆時の2024年9月6日時点での最新バージョンは、v0.0.15です。
前回執筆時点から3回更新されていました。
公式ドキュメントのページも結構追記されたようです。

本記事では、前回同様にv0.0.12を取り扱います。

https://github.com/microsoft/retina/


## 環境
本記事は、以下の環境での動作内容をもとに執筆しています。

* OS：Ubuntu 22.04.4 LTS (Jammy Jellyfish)
* Linuxカーネル：v6.5.0
* Kubernetes：v1.29.5
* CNI：Calico v3.25.0
* Retina：v0.0.12

# メトリクスの詳細
各マシンにRetinaのエージェントを導入することで、マシンのネットワークに関するメトリクスを収集できます。
Kubernetesでは、Retinaは各ノードにDaemonSetとしてデプロイされます。
前回の構築作業で、Helmを使ってDaemonSetとしてデプロイ済みです。

収集できるメトリクスは設定によって異なるので、ドキュメントを参考にまとめます。

## メトリクスの出力形式
Retinaでは各エージェントが収集したメトリクスは、エンドポイントからOpenMetrics形式(いわゆるPrometheusの出力形式)で出力されます。
他の監視ツールでも広く採用されている出力形式なので、おなじみかと思います。

https://openmetrics.io/

こんなやつです。
```
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0.000122504
go_gc_duration_seconds{quantile="0.25"} 0.000163169
go_gc_duration_seconds{quantile="0.5"} 0.000228526
go_gc_duration_seconds{quantile="0.75"} 0.000392953
go_gc_duration_seconds{quantile="1"} 0.001000051
go_gc_duration_seconds_sum 0.003200799
go_gc_duration_seconds_count 9
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 111
```


## メトリクスのモード
Retinaで収集するメトリクスには、その対象範囲や分類粒度に応じ、大きく分けるとBasicとAdvancedの2つ、細かく分けるとAdvancedがlocal contextとremote contextの2つに分かれて計3つのモードがあります。

Advencedモードで収集されるメトリクスは、基本的にBasicで収集されるメトリクスを含みます。
表にまとめるとこんな感じです。

:::note
本記事では分かりやすさのために、公式ドキュメントからモードの並び順を変えています。詳細度とスケールは著者の判断で追記しています。
:::

|モード|レベル|コンテキスト|詳細|詳細度|スケール|
|:-:|:-:|:-:|:--|:-:|:-:|
|Basic|ノード|-|一番シンプルなノードごとのメトリクス。|△|◎|
|Advanced/Pod-Level<br>with local context|Pod|local|通信相手を区別せず手元のPodごとに集計したメトリクス。|○|○|
|Advanced/Pod-Level<br>with remote context|Pod|remote|送信元と宛先のPodそれぞれごとに集計したメトリクス。組合せが膨大になる。|◎|△|

### モードの指定
モードの指定は、デプロイ時のオプションまたは`values.yaml`ファイル(ConfigMap)で指定します。

`enablePodLevel`オプションを`true`に設定すると、Advancedモードになります。
`remoteContext`オプションを`true`に設定すると、remoteコンテキストになります。
上記オプションをいずれも指定しないとデフォルトのBasicモードになります。

前回の記事では、Basicモードでデプロイする手順を示していました。
Advancedモードを使用する場合は、上記の2つのオプションをデプロイ時に適宜指定してください。


### モードの詳細
ここまでの説明ではモード間の具体的な違いがよく分からないので、各モードで収集される実際のメトリクスを見ていきましょう。

#### Basic
Basicモードでは、ノード単位で集約される一番基本的なネットワークのメトリクスを収集できます。

実際のメトリクス例は次の通りです。
この例はDNSクエリに関するメトリクス(`networkobservability_dns_request_count`)です。

```
networkobservability_dns_request_count{num_response="0",query="elasticsearch-master.default.svc.cluster.local.",query_type="A",response="",return_code=""} 72
```
この例では、ノード上で稼働するすべてのPodからドメイン`elasticsearch-master.default.svc.cluster.local.`についてのタイプAのDNSクエリが合計で72件あったことを示しています。

:::note
Retinaが提供するメトリクスの名前には、プレフィックスとして`networkobservability_`が付きます。
:::

#### Advanced/Pod-Level with local context
Advanced/Pod-Level with local contextモードでは、ノードに存在するPod単位で集計したネットワークのメトリクスを収集できます。
つまり、アウトバンド通信の送信元となるPod、インバウンド通信の宛先となるPodごとにメトリクスが集計されます。

実際のメトリクスは次の通りです。
Advencedモードでは、メトリクス名に`adv`の文字列が追加され、`networkobservability_adv_dns_request_count`となっています。

```
networkobservability_adv_dns_request_count{ip="192.168.2.57",namespace="default",num_response="0",podname="apm-apm-server-58c8c78b76-hgngs",query="elasticsearch-master.default.svc.cluster.local.",query_type="A",response="",return_code="",workload_kind="ReplicaSet",workload_name="apm-apm-server-58c8c78b76"} 18
```
この例から分かるように、ローカルのPod`apm-apm-server-58c8c78b76`から送信されるDNSクエリは、宛先のDNSサーバーを問わずに合計値として集計されています。
Kubernetesクラスター内で使用されるDNSのCoreDNSは、通常、複数のPodがデプロイされるためクエリも分散しますが、これらをまとめて集計するということです。

Basicのメトリクスと比べて、ラベルが5個増えました。
これらのラベルによって、今回の場合クエリ送信元Podが識別できるようになっています。

**増えたラベル**
* `ip`：計測対象のローカルのPodのIPアドレス
* `namespace`：計測対象のローカルのPodが属するネームスペース
* `podname`：計測対象のローカルのPodの名前
* `workload_kind`：計測対象のローカルのPodを管理するワークロードの種類(ReplicaSet、DaemonSetなど)
* `workload_name`：計測対象のローカルのPodを管理するワークロードの名前


#### Advanced/Pod-Level with remote context
Advanced/Pod-Level with remote contextモードでは、通信の送信元・送信先の対ごとに集計したネットワークのメトリクスを収集できます。
例えば、通信がDNSラウンドロビンで負荷分散されている場合だと、分散先のIPアドレスごとに分けて集計されます。

実際のメトリクスは次の通りです。
メトリクス名は、local contextと同様に`networkobservability_adv_dns_request_count`となっています。

```
networkobservability_adv_dns_request_count{destination_ip="192.168.2.9",destination_namespace="kube-system",destination_podname="coredns-76f75df574-lgk44",destination_workload_kind="ReplicaSet",destination_workload_name="coredns-76f75df574",num_response="0",query="elasticsearch-master.default.svc.cluster.local.",query_type="A",response="",return_code="",source_ip="192.168.2.57",source_namespace="default",source_podname="apm-apm-server-58c8c78b76-hgngs",source_workload_kind="ReplicaSet",source_workload_name="apm-apm-server-58c8c78b76"} 107
```
この例から分かるように、ローカルのPod`apm-apm-server-58c8c78b76`から送信されるDNSクエリのうち、宛先であるDNSのPodが`coredns-76f75df574-lgk44`のもののみが集計されています。

ラベルは送信元と送信先を区別できるように、`source_`と`destination_`のプレフィックスが追加されたため、local contextの2倍、Basicと比べて10個増えました。
総勢で以下の通りです。

**増えたラベル**
* `source_ip`
* `source_namespace`
* `source_podname`
* `source_workload_kind`
* `source_workload_name`
* `destination_ip`
* `destination_namespace`
* `destination_podname`
* `destination_workload_kind`
* `destination_workload_name`

ここまで読まれた方はお気づきかもしれませんが、Advanced/Pod-Level with remote contextモードでは、通信の送信元・送信先の対ごとに集計されるため、送信元、送信先が増えると収集されるメトリクスの数が一気に増加します。
上記の例では、メトリクス1つのみを抜粋しているため、その多さが分かりづらいのですが、実際にRetinaのエージェントがエンドポイントに出力するメトリクスは、今回の場合約2倍になりました。

大規模なシステムでは、すべての通信を監視対象とするのは非現実的なため、監視対象を絞る必要がありそうです。
後述しますが、Retinaには監視対象のPodを絞る機能も提供されています。


## メトリクスの項目
Retinaでは、収集するメトリクスはプラグインをオンオフすることで指定します。

一般的なLinuxで使える標準的なプラグインは、現時点で以下の6つがあります。
最後の2つの`packetparser`と`tcpretrans`は、Advancedモード限定のプラグインです。
* `packetforward`
* `dropreason`
* `linuxutil`
* `dns`
* `packetparser`
* `tcpretrans`

:::note
この他に、NVIDIA Infiniband用のプラグイン`infiniband`やWindows用のプラグイン`hnsstats`があります。プラグインは今後も増えていく気配があります。
:::

詳しく説明していませんでしたが、実は前回の記事でRetinaをデプロイする時に`enabledPlugin_linux`オプションで有効にするプラグインを指定していました。
なお、`values.yaml`ファイル(ConfigMap)で指定することもできます。
```
--set enabledPlugin_linux="\[dropreason\,packetforward\,linuxutil\,dns\,packetparser\]"
```


それぞれのメトリクスをもう少し詳しく見てみましょう。

:::note
ある程度詳しく解説していきますが、公式ドキュメントもご参照ください。各プラグインで収集されるメトリクスの一覧など詳しい情報が掲載されています。
:::

https://retina.sh/docs/Metrics/plugins/


### `packetforward`
`packetforward`プラグインは、ノードの`eth0`インターフェースから送受信されたパケットの情報(パケット数とバイト数)を収集します。
情報の収集には、eBPFが使用されています。

収集されるメトリクスは、次の2つです。
* `forward_count`
* `forward_bytes`

ラベルとして`direction`があり、トラフィックの向きごとに集計されます。

実際に収集してみた値(抜粋)は次の通りです。

```
# HELP networkobservability_forward_bytes Total forwarded bytes
# TYPE networkobservability_forward_bytes gauge
networkobservability_forward_bytes{direction="egress"} 2.3747137e+07
networkobservability_forward_bytes{direction="ingress"} 2.7649847e+07
# HELP networkobservability_forward_count Total forwarded packets
# TYPE networkobservability_forward_count gauge
networkobservability_forward_count{direction="egress"} 54685
networkobservability_forward_count{direction="ingress"} 54158
```

### `dropreason`
`dropreason`プラグインは、ノードでドロップされたパケットの情報(パケット数とバイト数)を収集します。
情報の収集には、eBPFが使用されています。

収集されるメトリクスは、次の2つです。
Advancedモードかどうかでプレフィックスに`adv_`が付くかが変わります。
* `drop_count`/`adv_drop_count`
* `drop_bytes`/`adv_drop_bytes`

ラベルとして`direction`と`reason`があり、トラフィックの向きごと及びドロップされた理由ごとに集計されます。
また、Advancedモードではコンテキストを示すラベルが追加されます。

ドロップされた理由は、iptablesのルールやTCPの接続状態などいくつかあり、今後も追加されるようです。
> This list will keep on growing as we add support for more reasons.

引用元：https://retina.sh/docs/Metrics/plugins/dropreason#ebpf-hook-points-for-drop-reason


実際に収集してみた値(抜粋)は次の通りです。
```
# HELP networkobservability_drop_bytes Total dropped bytes
# TYPE networkobservability_drop_bytes gauge
networkobservability_drop_bytes{direction="unknown",reason="CONNTRACK_ADD_DROP"} 103
# HELP networkobservability_drop_count Total dropped packets
# TYPE networkobservability_drop_count gauge
networkobservability_drop_count{direction="unknown",reason="CONNTRACK_ADD_DROP"} 1
```

### `linuxutil`
`linuxutil`プラグインは、TCP/UDPの統計とネットワークインターフェースの統計を収集します。
このプラグインは、eBPFではなく、Linuxコマンドで情報を収集します。

TCP/UDPの統計の取得には`netstats`コマンドが使用されます。
メトリクスを以下の表に示します。
ラベルでさらに分類されるため、実際に出力されるメトリクスの量は多くなります。
|メトリクス名|概要|ラベル|
|:--|:--|:--|
|`tcp_state`|TCPの状態ごとのアクティブなソケット数|`state`<br>(例：`ESTABLISHED`, `TIME_WAIT`など)|
|`tcp_connection_remote`|TCPのリモートのアドレス/ポートごとのアクティブなソケット数|`ip`, `port`|
|`tcp_connection_stats`|TCP接続の各種統計値|`statistic_name`<br>(例：`TCPTimeouts`, `ResetCount`など)|
|`ip_connection_stats`|IP接続の各種統計値|`statistic_name`<br>(例：`InNoECTPkts`, `InOctets`など)|
|`udp_connection_stats`|UDP接続の各種統計値|`statistic_name`<br>(`ACTIVE`のみ)|


実際に収集してみた値(抜粋)は次の通りです。
```
# HELP networkobservability_ip_connection_stats IP connections Statistics
# TYPE networkobservability_ip_connection_stats gauge
networkobservability_ip_connection_stats{statistic_name="InBcastOctets"} 7.0064712e+07
networkobservability_ip_connection_stats{statistic_name="InBcastPkts"} 552774
networkobservability_ip_connection_stats{statistic_name="InECT0Pkts"} 170
networkobservability_ip_connection_stats{statistic_name="InMcastOctets"} 3.231457e+07
# HELP networkobservability_tcp_connection_remote number of active TCP connections by remote address
# TYPE networkobservability_tcp_connection_remote gauge
networkobservability_tcp_connection_remote{address="10.96.0.1",port="443"} 4
networkobservability_tcp_connection_remote{address="10.96.0.10",port="9153"} 1
networkobservability_tcp_connection_remote{address="10.96.82.33",port="5601"} 5
# HELP networkobservability_tcp_connection_stats TCP connections Statistics
# TYPE networkobservability_tcp_connection_stats gauge
networkobservability_tcp_connection_stats{statistic_name="DelayedACKLocked"} 2159
networkobservability_tcp_connection_stats{statistic_name="DelayedACKLost"} 160625
networkobservability_tcp_connection_stats{statistic_name="DelayedACKs"} 4.567785e+06
# HELP networkobservability_tcp_state number of active TCP connections by state
# TYPE networkobservability_tcp_state gauge
networkobservability_tcp_state{state="ESTABLISHED"} 46
networkobservability_tcp_state{state="LISTEN"} 14
networkobservability_tcp_state{state="TIME_WAIT"} 161
# HELP networkobservability_udp_connection_stats UDP connections Statistics
# TYPE networkobservability_udp_connection_stats gauge
networkobservability_udp_connection_stats{statistic_name="ACTIVE"} 9
```

ネットワークインターフェースの統計の取得には`ethtool`コマンドが使用されます。
メトリクスを以下の表に示します。
|メトリクス名|概要|ラベル|
|:--|:--|:--|
|`interface_stats`|インターフェースの各種統計値|`interface_name`,<br>`statistic_name`<br>(例：`tx_packets`, `rx0_cache_full`など)|

実際に収集してみた値(抜粋)は次の通りです。
```
# HELP networkobservability_interface_stats Interface Statistics
# TYPE networkobservability_interface_stats gauge
networkobservability_interface_stats{interface_name="califf2681400cb",statistic_name="peer_ifindex"} 3
networkobservability_interface_stats{interface_name="ens160",statistic_name="  LRO byte rx"} 2.1697016e+07
networkobservability_interface_stats{interface_name="ens160",statistic_name="  LRO pkts rx"} 9258
networkobservability_interface_stats{interface_name="ens160",statistic_name="  TSO bytes tx"} 5.7979568065e+10
networkobservability_interface_stats{interface_name="ens160",statistic_name="  TSO pkts tx"} 1.2924301e+07
networkobservability_interface_stats{interface_name="ens160",statistic_name="  bcast bytes rx"} 5.0642304e+07
```



### `dns`
`dns`プラグインは、DNSのトラフィックやクエリの情報を収集します。
このプラグインは、[Inspektor GadgetのDNS Tracer](https://www.inspektor-gadget.io/docs/latest/gadgets/trace_dns)によって情報を収集しているそうです。
DNS Tracer自体はeBPFを使っているようです。

収集されるメトリクスは、次の2つです。
Advancedモードかどうかでプレフィックスに`adv_`が付くかが変わります。
* `dns_request_count`/`adv_dns_request_count`
* `dns_response_count`/`adv_dns_response_count`

ラベルとして以下の5つがあり、クエリやそのレスポンスに応じて細かく分類されます。
また、Advancedモードではコンテキストを示すラベルが追加されます。
* `query_type`
* `query`
* `return_code`
* `response`
* `num_response`


実際に収集してみた値(抜粋)は次の通りです。
```
# HELP networkobservability_adv_dns_request_count Total number of DNS query packets
# TYPE networkobservability_adv_dns_request_count counter
networkobservability_adv_dns_request_count{ip="192.168.2.13",namespace="zabbix",num_response="0",podname="zabbix-zabbix-agent-4ntsz",query="zabbix-zabbix-server.zabbix.svc.cluster.local.",query_type="A",response="",return_code="",workload_kind="DaemonSet",workload_name="zabbix-zabbix-agent"} 2
networkobservability_adv_dns_request_count{ip="192.168.2.13",namespace="zabbix",num_response="0",podname="zabbix-zabbix-agent-4ntsz",query="zabbix-zabbix-server.zabbix.svc.cluster.local.",query_type="AAAA",response="",return_code="",workload_kind="DaemonSet",workload_name="zabbix-zabbix-agent"} 2
# HELP networkobservability_adv_dns_response_count Total number of DNS response packets
# TYPE networkobservability_adv_dns_response_count counter
networkobservability_adv_dns_response_count{ip="192.168.2.13",namespace="zabbix",num_response="0",podname="zabbix-zabbix-agent-4ntsz",query="zabbix-zabbix-server.zabbix.svc.cluster.local.",query_type="AAAA",response="",return_code="NOERROR",workload_kind="DaemonSet",workload_name="zabbix-zabbix-agent"} 2
networkobservability_adv_dns_response_count{ip="192.168.2.13",namespace="zabbix",num_response="0",podname="zabbix-zabbix-agent-4ntsz",query="zabbix-zabbix-server.zabbix.svc.cluster.local.cluster.local.",query_type="A",response="",return_code="NXDOMAIN",workload_kind="DaemonSet",workload_name="zabbix-zabbix-agent"} 2
```

### `packetparser`
`packetparser`プラグインは、ノードの`eth0`インターフェースを通過したTCPパケットのパケットの情報(パケット数、バイト数、TCPフラグごとのパケット数)を収集します。
また、KubernetesのAPIサーバーとのレイテンシーを収集します。
Advancedモード専用のプラグインです。
情報の収集には、eBPFが使用されています。

メトリクスを以下の表に示します。
|メトリクス名|概要|ラベル|
|:--|:--|:--|
|`adv_forward_count`|フォワードされたパケット数|`direction`|
|`adv_forward_bytes`|フォワードされたバイト数|`direction`|
|`adv_tcpflags_count`|フラグごとのTCPパケット数|`flag`|
|`adv_node_apiserver_latency`|APIサーバーの通信レイテンシー(ヒストグラム)|`le`|
|`adv_node_apiserver_no_response`|APIサーバーから応答がなかったパケット数|-|
|`adv_node_apiserver_tcp_handshake_latency`|APIサーバーとの接続確立時のレイテンシー(ヒストグラム)|`le`|

`adv_forward_xxx`に関しては、`direction`ラベルでトラフィックの向きごとに集計されます。
また、コンテキストのラベルも追加されます。
APIサーバー関係のメトリクスのうち、レイテンシーについては、ヒストグラムが提供されます。

実際に収集してみた値(抜粋)は次の通りです。
`adv_node_apiserver_no_response`は発生しなかったので含まれません。
```
# HELP networkobservability_adv_forward_bytes Total number of forwarded bytes
# TYPE networkobservability_adv_forward_bytes gauge
networkobservability_adv_forward_bytes{direction="egress",ip="192.168.0.211",namespace="kube-system",podname="prometheus-kube-prometheus-operator-57d56558d8-8fgjd",workload_kind="ReplicaSet",workload_name="prometheus-kube-prometheus-operator-57d56558d8"} 3.7705763e+07
networkobservability_adv_forward_bytes{direction="ingress",ip="192.168.0.211",namespace="kube-system",podname="prometheus-kube-prometheus-operator-57d56558d8-8fgjd",workload_kind="ReplicaSet",workload_name="prometheus-kube-prometheus-operator-57d56558d8"} 2.19086691e+08
# HELP networkobservability_adv_forward_count Total number of forwarded packets
# TYPE networkobservability_adv_forward_count gauge
networkobservability_adv_forward_count{direction="egress",ip="192.168.0.211",namespace="kube-system",podname="prometheus-kube-prometheus-operator-57d56558d8-8fgjd",workload_kind="ReplicaSet",workload_name="prometheus-kube-prometheus-operator-57d56558d8"} 386240
networkobservability_adv_forward_count{direction="ingress",ip="192.168.0.211",namespace="kube-system",podname="prometheus-kube-prometheus-operator-57d56558d8-8fgjd",workload_kind="ReplicaSet",workload_name="prometheus-kube-prometheus-operator-57d56558d8"} 357215
# HELP networkobservability_adv_node_apiserver_latency Latency of node apiserver in ms
# TYPE networkobservability_adv_node_apiserver_latency histogram
networkobservability_adv_node_apiserver_latency_bucket{le="0"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="0.5"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="1"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="1.5"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="2"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="2.5"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="3"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="3.5"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="4"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="4.5"} 0
networkobservability_adv_node_apiserver_latency_bucket{le="+Inf"} 0
networkobservability_adv_node_apiserver_latency_sum 0
networkobservability_adv_node_apiserver_latency_count 0
# HELP networkobservability_adv_node_apiserver_tcp_handshake_latency Latency of node apiserver tcp handshake in ms
# TYPE networkobservability_adv_node_apiserver_tcp_handshake_latency histogram
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="0"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="0.5"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="1"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="1.5"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="2"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="2.5"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="3"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="3.5"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="4"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="4.5"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_bucket{le="+Inf"} 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_sum 0
networkobservability_adv_node_apiserver_tcp_handshake_latency_count 0
# HELP networkobservability_adv_tcpflags_count Total number of packets by TCP flag
# TYPE networkobservability_adv_tcpflags_count gauge
networkobservability_adv_tcpflags_count{flag="ACK",ip="192.168.0.211",namespace="kube-system",podname="prometheus-kube-prometheus-operator-57d56558d8-8fgjd",workload_kind="ReplicaSet",workload_name="prometheus-kube-prometheus-operator-57d56558d8"} 743455
networkobservability_adv_tcpflags_count{flag="SYN",ip="192.168.0.212",namespace="kube-system",podname="prometheus-grafana-d5679d5d7-4hhcq",workload_kind="ReplicaSet",workload_name="prometheus-grafana-d5679d5d7"} 28504
networkobservability_adv_tcpflags_count{flag="SYNACK",ip="192.168.0.212",namespace="kube-system",podname="prometheus-grafana-d5679d5d7-4hhcq",workload_kind="ReplicaSet",workload_name="prometheus-grafana-d5679d5d7"} 28504
```

### `tcpretrans`
`tcpretrans`プラグインは、TCP再送信パケットの数を収集します。
Advancedモード専用のプラグインです。
情報の収集には、eBPFが使用されています。

収集されるメトリクスは、次の1つです。
* `adv_tcpretrans_count`

コンテキストのラベルが追加されます。

実際に収集してみた値(抜粋)は次の通りです。
```
# HELP networkobservability_adv_tcpretrans_count Total number of TCP retransmitted packets
# TYPE networkobservability_adv_tcpretrans_count gauge
networkobservability_adv_tcpretrans_count{destination_ip="10.104.125.176",destination_namespace="unknown",destination_podname="unknown",destination_workload_kind="unknown",destination_workload_name="unknown",direction="EGRESS",source_ip="192.168.2.7",source_namespace="zabbix",source_podname="zabbix-zabbix-web-5fc7d4f4f9-kctzj",source_workload_kind="ReplicaSet",source_workload_name="zabbix-zabbix-web-5fc7d4f4f9"} 350
```

# 監視対象の設定
Retinaでは、様々なプラグインを有効にすることでいろいろなメトリクスを収集できることが分かりました。
それでは次は、メトリクスの収集対象をどのように設定するか見ていきましょう。


## アノテーションによる指定
Retinaをそのままデプロイしただけではメトリクスの収集対象を絞ることはできませんが、アノテーション機能を有効にすることで、特定のアノテーションが付与されたリソースだけを対象とすることができます。
この機能を有効にするには、デプロイ時または`values.yaml`ファイル(ConfigMap)で`enableAnnotations`オプションを`true`に指定します。

機能を有効にすると、個々のPodまたはネームスペースにアノテーション`retina.sh: observe`を付与することで、収集対象を任意に指定できるようになります。
ネームスペースにアノテーションを付与した場合は、そのネームスペースに属するすべてのPodが監視対象となります。
リソースへのアノテーションの付与は、通常と同じく`kubectl annotate`コマンドで実行できます。
手元で試した限りでは、アノテーションを付与してからほぼリアルタイムで収集対象に加えられること確認しました。

:::note
現時点では、アノテーション機能を有効にすると`kube-system`に属するすべてのPodが監視対象となる仕様のようです。
> An exception: currently all Pods in kube-system are always monitored.

引用元：https://retina.sh/docs/Metrics/annotations
:::

## カスタムリソース定義(CRD)による設定
やや発展的な設定方法として、Kubernetesのカスタムリソース定義(CRD)を使用した設定方法も用意されています。
前章の話も含まれますが、収集するメトリクスや含めるラベル、収集対象/除外対象のネームスペースを`MetricsConfiguration`リソースとして定義することで設定が有効になります。
具体的には、CRDのマニフェストをYAMLファイルに書き出し、`kubectl apply`コマンドで適用します。

YAMLファイルの例は次の通りです。

```metrics_config.yaml
apiVersion: retina.sh/v1alpha1
kind: MetricsConfiguration
metadata:
  name: metricsconfig-hogehoge
spec:
  contextOptions:
    - metricName: drop_count
      sourceLabels:
        - ip
        - podname
        - port
      additionalLabels:
        - direction
namespaces:
    include:
      - hogehoge
      - kube-system
```


# まとめ
今回はKubernetesクラスターのオブザーバビリティプラットフォームであるRetinaで収集できるメトリクスやその設定方法について詳しく見てきました。
プラグインやアノテーションにより、必要な情報を必要なリソースに絞って収集できるのは手軽で便利だと思います。
また、ドキュメントを見るたびに記載事項が少しずつ増えていて、日々機能追加・改良されていることを感じます。

Retinaはまだ世に出たばかりということもあって、未実装の機能や細かいバグがあります。
気づいたものは今後時間があればコントリビュートしていきたいなと思っています。

次回は、Retinaの目玉機能のもう1つ、キャプチャ機能ついて詳しく見ていきたいと思います。

最後までお読みいただきありがとうございました。
ご質問やコメントもお待ちしております。


【2025/1/24追記】
続編の記事はこちらです。

https://qiita.com/melknzw/items/563cfcdcf5ff76917d6a