kube-prometheusを導入したらkubectl top nodeでエラーになる

# はじめに

kubesprayでmetricsを有効にした状態から、これを削除し、kube-prometheusを導入しました。

v0.12.0なkube-prometheusのバグで``$ kubectl top node`` が動作しなかったため、その顛末をメモしておきます。

# 環境

* kubespray v2.21.0 (kubernetes: v1.25.6)
* kube-prometheus v0.12.0

# 参考資料

* GitHub Issues #926 - [Document guidance to remove metrics-server before installing kube-prometheus](https://github.com/prometheus-operator/kube-prometheus/issues/926)
* GitHub Issues #1764 - [prometheus-adapter: failed querying node metrics](https://github.com/prometheus-operator/kube-prometheus/issues/1764)

# 準備作業

kubesprayのaddons.ymlでmetrics-serverを有効にしていた場合の対処は次のセクションに記載しています。

その他にnode-exporterをパッケージなどで導入していた場合には、kube-prometheusと競合するため事前にアンインストールが必要です。

```bash:
$ sudo apt remove prometheus-node-exporter
```

# 変更点

## kube-prometheus導入前の作業

既に導入されているmetrics-serverがある場合には、次の要領で削除します。
ない場合には飛してkube-prometheusの導入に進んでください。

```bash:リソース削除用のスクリプト
#!/bin/bash

sudo kubectl delete service/metrics-server -n  kube-system
sudo kubectl delete deployment.apps/metrics-server  -n  kube-system
sudo kubectl delete apiservices.apiregistration.k8s.io v1beta1.metrics.k8s.io
sudo kubectl delete clusterroles.rbac.authorization.k8s.io system:aggregated-metrics-reader
sudo kubectl delete clusterroles.rbac.authorization.k8s.io system:metrics-server 
sudo kubectl delete clusterrolebinding metrics-server:system:auth-delegator
sudo kubectl delete clusterrolebinding system:metrics-server          
sudo kubectl delete rolebinding metrics-server-auth-reader -n kube-system 
sudo kubectl delete serviceaccount metrics-server -n kube-system
```

関係のないリソースを削除しないように気をつけてください。

kubesprayのaddons.ymlを利用してmetrics-serverを導入していた場合には、関連するYAMLファイルがnode1の/etc/kubernetes/addons/metrics_server/ に配置されているので、これを利用しても良いと思います。

```bash:kubesprayのYAMLファイルを利用して削除する例
$ sudo kubectl delete -f /etc/kubernetes/addons/metrics_server/
```

## kube-prometheus導入後の作業

導入自体の手順は別の記事にまとめています。この記事に対応策をまとめています。

* [Qiita - kube-prometheusをjsonnet-builderでカスタマイズした時の対応メモ](https://qiita.com/YasuhiroABE/items/dca43cff82d7991658fa) 

これで導入したところ次のようなエラーになりました。

```bash:エラー例
$ sudo kubectl top node
error: metrics not available yet
```

これを解決するためには、参考資料に挙げた#1764の手順のように、promethesのnetworkpolicyにadapterからの通信を許可してあげる必要があります。

```bash:
$ sudo kubectl -n monitoring  edit networkpolicy prometheus-k8s
```

エディタが起動したらgrafanaの定義をコピーして、kube-prometheusを加えてあげます。

```yaml:追加する断片
  - from:
    - podSelector:
        matchLabels:
          app.kubernetes.io/name: prometheus-adapter
    ports:
    - port: 9090
      protocol: TCP
```

前後の差分は次のようになっています。

```diff:
--- a.yaml      2023-03-15 05:04:40.490062834 +0000
+++ b.yaml      2023-03-15 05:04:31.238491762 +0000
@@ -36,6 +36,13 @@
     ports:
     - port: 9090
       protocol: TCP
+  - from:
+    - podSelector:
+        matchLabels:
+          app.kubernetes.io/name: prometheus-adapter
+    ports:
+    - port: 9090
+      protocol: TCP
   podSelector:
     matchLabels:
       app.kubernetes.io/component: prometheus
```

これでkubectl topが反応するようになるはずです。

# top nodeには対応するけれど、top podがエラーになる

ここまでの対応で改善すれば良いのですが、top nodeには反応するけれど、top podが動作しないという現象にも遭遇しました。

```bash:エラーの例
$ sudo kubectl top node
NAME    CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
node1   1234m        15%    7260Mi          24%
node2   682m         17%    7056Mi          45%
node3   697m         17%    3785Mi          24%
node4   790m         19%    6700Mi          42%

$ sudo kubectl -n monitoring top pod
error: Metrics not available for pod monitoring/alertmanager-main-0, age: 36m15.420243139s
```

関連しそうな報告には次のようなものが挙げられます。

* https://stackoverflow.com/questions/71692797/prometheus-adapter-unable-to-fetch-cpu-metrics-for-pod-podname-skipping
* https://github.com/kubernetes-sigs/prometheus-adapter/issues/496
* https://github.com/kubernetes-sigs/prometheus-adapter/issues/385
* https://github.com/prometheus-operator/kube-prometheus/issues/926

## 原因の調査

"Metrics not available for pod"で検索すると、次のIssuesがmetrics-serverで報告されています。
 
* [https://github.com/kubernetes-sigs/metrics-server/issues/1061](https://github.com/kubernetes-sigs/metrics-server/issues/1061)

これはmetrics-server用のものなので、直接はkube-state-metricsとは関係ありませんが、どうもdockershimが悪さをしているという指摘があります。

kubesprayではcri-dockerdを利用しているため、これをcontainerdに変更することで挙動の変更を確認します。

kubesprayでは以下の文書で、dockerdからcontainerdへのマイグレーションガイドを提供しています。

* [https://github.com/kubernetes-sigs/kubespray/blob/master/docs/upgrades/migrate_docker2containerd.md](https://github.com/kubernetes-sigs/kubespray/blob/master/docs/upgrades/migrate_docker2containerd.md)

この結果、top podは無事に動作しました。

```bash:top podの実行結果
$ sudo kubectl top pod -A

NAMESPACE        NAME                                              CPU(cores)   MEMORY(bytes)
ingress-nginx    ingress-nginx-controller-2whld                    1m           120Mi
ingress-nginx    ingress-nginx-controller-4p7fb                    1m           123Mi
ingress-nginx    ingress-nginx-controller-6p2ft                    1m           122Mi
ingress-nginx    ingress-nginx-controller-zdqv4                    2m           165Mi
kube-system      calico-kube-controllers-75748cc9fd-5cks7          4m           22Mi 
kube-system      calico-node-gq89c                                 50m          136Mi
kube-system      calico-node-m74b8                                 40m          141Mi
kube-system      calico-node-qrz8x                                 35m          133Mi
```

ノードの変更は1台づつ実施しましたが、containerdに置き換わったノードから結果が返ってくるようになりました。

まだcri-dockerdから具体的にどんな出力があって問題が発生したのか確認できていませんが、いまのところdockerdからcontainerdへのmigrationが可能な回避策のようです。

以上