TL;DR
NetworkManagerとの競合を防ぐためNetworkManagerで一部インターフェイスはマネジメントしないように設定する。
calico daemonsetsのIP_AUTODETECTION_METHODをfirst-foundからcidrsに切り替えることでちゃんと通信先のNICを指定する。
タイトルの通り。
kubernetesクラスタを構築する際にcalicoの設定をサボった結果あとから痛い目に遭遇したのでそれの共有でもしていきます。
我が家のkubernetesはCNIにcalicoを使っており、特別な設定をせずにQuick Startそのまんまでデプロイしていた。
しばらくはそれでPodにちゃんとIPアドレスが割り当てられていたし、Ingressを設定しても問題なく疎通があった。
さて、しばらくはそんな感じでいくつかのPodを上げては壊しを繰り返しいろいろ実験していました。
そうするとやはりというかなんというか、リソース不足に陥るわけです。
特にメモリが不足しており、OOM Killが走り他のノードに割り当て直されそこでもOOM Killが走り・・・ということが起きていました。
というわけで普段踏み台としてしか使っていないそれなりにスペックのあるミニPCと普段はゲームくらいでしか酷使されないメインマシンをKubernetesクラスタに突っ込んでしまうことにしました。
普段踏み台とかメインとして使っているホストをKubernetesのノードとして動かす試みというのはあまりないわけですので、まあいろいろ面倒は出てきます。
その最たる例はcalicoでした。
calicoはCNI Container Network Interface Pluginと呼ばれるものでコンテナ間のネットワークを司るKubernetesのネットワークプラグインです。
このcalicoが例の新しく追加しようとしたノード上ではうまく動きませんでした。
その原因は以下2つです。
NetworkManagerとの競合
Interfaceの疎通不可能NICを自動選択したことによる疎通不可能状態
NetworkManagerとの競合
これはかなり有名なお話のようでcalicoの公式ドキュメントのTrouble Shootingのところに記載あるのでこちらを参照してもらえればなと思います。
https://docs.tigera.io/calico/latest/operations/troubleshoot/troubleshooting
NetworkManagerがcalicoのルーティングテーブルと競合した結果、calicoのルーティングの方を優先させようとしたと思われますがデフォルトゲートウェイのmetricがものすごい大きい数が割り当てられており、あらゆる通信がcalicoの方に流れるという問題が生じました。
その結果ホスト自体の通信が落ちてしまいSSHもつながらないとひどい状態に陥りました。
というわけで、そうならないようにNetworkManager側にはそれを是正するような設定を記載しました。
[keyfile] unmanaged-devices=interface-name:cali*;interface-name:tunl*;interface-name:vxlan.calico;interface-name:vxlan-v6.calico;interface-name:wireguard.cali;interface-name:wg-v6.cali
ひとまずNetworkManager関連の競合問題はこれで解決しました。
Interfaceの疎通不可能NICを自動選択したことによる疎通不可能状態
こちらは仕事の忙しさも相まってかなり長い期間悩まされてきましたが、昨日ようやく解決に至ったのでご報告いたします。
この問題はまず最初稀にIngressの疎通ができないな〜という問題から始まりました。
そのときは稀に通信ができない程度だったのでDNSが原因だろうかとcorednsの設定を見たりなんやらしていた記憶があります。
Pod自体の問題かとか、Serviceリソースの設定がなにかおかしいのかとかかなり的外れなことを調べていましたが、
なんだかんだいろいろ試していくうちに新しく追加したミニPCとメインマシンへのPodのみ通信ができなくなるということが分かりました。
その頃は、まあいろいろあって一部システムを止めていたこともあったので一旦ノードをcordonしてどう解決していこうか検討していこうということでお茶を濁しました。
その結果、いろいろ仕事が忙しかったり、なんか6月病みたいなものになって休日も何もできない日々がずーっと続いていたので放置していました。
k8s自体も放置していましたし、まだモニタリングシステムもなんの整備もしていないのでアラートが鳴るということもなかったわけです。
そうこう過ごしてるうちに、またおうちk8sをいじりたいという気持ちが昂ぶり、さあいじるか〜 -> あれリソース足らねえ -> あ、cordonしてたわ〜と長い間放置していた前の記憶を掘り起こし、重い腰上げて根本原因調査するか〜とはじめました。
お仕事でもKubernetesクラスタのメンテナンスや障害対応をしていたため、だいぶ見るべきところが見えてきて数ヶ月前になんとな〜く公式ドキュメント通りにデプロイしたcalicoが怪しいな〜とたどりつきました。
見てみると、なんと一部ホストでcalico-node-***というPodがちゃんと動いていないと
$ k get pods -n calico-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-558b7d9cf4-rslz8 1/1 Running 313 (22h ago) 227d calico-node-28xr4 1/1 Running 23 (7h2m ago) 227d calico-node-45xkr 1/1 Running 0 10d calico-node-5qrz5 1/1 Running 16 (10d ago) 226d calico-node-6xjgq 1/1 Running 0 10d calico-node-fkf9d 1/1 Running 16 (10d ago) 227d calico-node-k62hq 1/1 Running 22 (8d ago) 76d calico-node-nnjkr 1/1 Running 25 (44d ago) 227d calico-node-smxkd 0/1 Running 0 38m calico-node-snq2d 1/1 Running 25 227d calico-typha-996fb9cc7-fgtms 1/1 Running 21 (44d ago) 227d calico-typha-996fb9cc7-m8ftm 1/1 Running 27 (10d ago) 227d calico-typha-996fb9cc7-tdg8k 1/1 Running 20 (44d ago) 227d csi-node-driver-4c62z 2/2 Running 42 (8d ago) 81d csi-node-driver-6blck 2/2 Running 26 (44d ago) 227d csi-node-driver-7rqxd 2/2 Running 0 10d csi-node-driver-cnzcp 2/2 Running 32 (10d ago) 226d csi-node-driver-d5mss 2/2 Running 27 (44d ago) 227d csi-node-driver-fldqr 2/2 Running 0 38d csi-node-driver-s2jpt 2/2 Running 32 (10d ago) 227d csi-node-driver-t6f4z 2/2 Running 0 10d csi-node-driver-xd8vc 2/2 Running 26 (44d ago) 227d
で、そのPodをdescribeしてみるとなーんかBIRDのconnectionがうまくいってないことが分かります。
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41m default-scheduler Successfully assigned calico-system/calico-node-smxkd to einsteinium Normal Pulled 41m kubelet Container image "docker.io/calico/pod2daemon-flexvol:v3.26.1" already present on machine Normal Created 41m kubelet Created container flexvol-driver Normal Started 41m kubelet Started container flexvol-driver Normal Pulled 41m kubelet Container image "docker.io/calico/cni:v3.26.1" already present on machine Normal Created 41m kubelet Created container install-cni Normal Started 41m kubelet Started container install-cni Normal Pulled 41m kubelet Container image "docker.io/calico/node:v3.26.1" already present on machine Normal Created 41m kubelet Created container calico-node Normal Started 41m kubelet Started container calico-node Warning Unhealthy 41m kubelet Readiness probe failed: calico/node is not ready: BIRD is not ready: Error querying BIRD: unable to connect to BIRDv4 socket: dial unix /var/run/calico/bird.ctl: connect: connection refused W0626 11:17:59.370689 24 feature_gate.go:241] Setting GA feature gate ServiceInternalTrafficPolicy=true. It will be removed in a future release. Warning Unhealthy 41m kubelet Readiness probe failed: calico/node is not ready: BIRD is not ready: Error querying BIRD: unable to connect to BIRDv4 socket: dial unix /var/run/calico/bird.ctl: connect: connection refused W0626 11:18:00.347606 62 feature_gate.go:241] Setting GA feature gate ServiceInternalTrafficPolicy=true. It will be removed in a future release. Warning Unhealthy 41m kubelet Readiness probe failed: 2024-06-26 11:18:07.119 [INFO][365] confd/health.go 180: Number of node(s) with BGP peering established = 0
さて、ここでまずはこのBIRDが使うであろうポート179が空いてるかなぁと見ていきますが案の定繋がりはするわけです。
https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements
$ curl *****:179 つながりはするけどホストのサービス側(calico)から落とされる $ telnet *****:179 上と同様
となると179ポート自体は閉じていない。
もちろんufw自体も停止しているので阻むものは何もありませんでした。
そうこうして調べていくうちに以下のstackoverflowにたどり着き、どうやらIP_AUTODETECTION_METHODを設定する必要があるということが分かりました。
jenkins - Kubernetes - Calico-Nodes 0/1 Ready - Stack Overflow
で、calicoインストール時にデプロイしたオペレータのコードを見ていくとnodeAddressAutoDetectionV4には他にもいくつか設定できる項目があり、その中にCIDRを設定できるということが分かりました。
https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/tigera-operator.yaml
お、これは勝利の予感。
というわけでcalicoのDaemonSetのnodeAddressAutoDetectionV4をホスト間通信用のNICが使っているCIDRにしてデプロイし直してようやく解決しました。