Open13

K8s on vSphereでPodを好きなネットワークにつなぎたい

おとうふおとうふ
  • Multus CNIを使うことでPodに複数のインターフェイスをつけれる
    • あるいはCiliumでもMulti-homingについてのproposalがある https://github.com/cilium/cilium/issues/20129
    • 追加インターフェイスに対するファイアウォールなどをどうするかという問題はまた考えないといけない
  • 好きなネットワークにつなぐには、当然そこにnodeがそもそもつながっている必要はある
  • 2つ方式が考えられそう
    • node用のVMに対しtrunk portにつないだvNICを追加で接続しておく方式
      • node上でVLANタグを見てsubinterfaceに割り振るようなことをすればよい
      • 標準であるCNIプラグイン bridge の VLAN フィルタでも行けるはず
      • 802.1QのVLANが大前提になってしまうというのはある
    • node用のVMに対し必要なポートグループを適宜つなぎに行く方式
      • (Cluster APIを使っている前提で)Cluster Autoscalerを使って必要に応じてnodeを追加すればいいのではないか
      • 冗長構成とかのためにPodたくさん配置とかする場合に大変そう…
        • 単にnodeにまたがってreplica配置できればいいならいいけど、nodeの乗ってるESXiホストをtopologyKeyにして…とか考えると、事前にESXiホストが何になるかわからないので、autoscaler的には判断がつかなさそう
      • CNI的にはtrunk port方式同様 bridge プラグインとかでなんとかなると思われる
おとうふおとうふ

node用のVMに対し必要なポートグループを適宜つなぎに行く方式

Whereabouts のようなIPAMを使えば、Podへのアドレスも良い感じに割当てできそうだった。

NetworkPolicy的な部分はなんともならない(CNIとして対応が必要になるところ)ので、firewall pluginなどを参考にプラグインを作るしかない?(ルールをある程度柔軟に受けられるようにするなら、PodのAnnotationや何らかのルールでConfigMapを取ってきて、それに従ったiptablesルールやBPFプログラムを差し込むようにする感じになる?)

おとうふおとうふ

cluster autoscaler (CAPI)試してみている。が、うまく行かない。

I0429 17:32:38.643359 1 pre_filtering_processor.go:57] Node ca-test-md-0-5d9cf48855-cq9zk should not be processed by cluster autoscaler (no node group config)

のようなログが出ている。
autodiscovery周りの設定を全部外しても変わらないので、 https://github.com/kubernetes/autoscaler/blob/f87dbe5fc65ae6a6c550b0c22d7910ec192e7cfb/cluster-autoscaler/cloudprovider/clusterapi/clusterapi_controller.go#L232 あたりでちゃんとMachineDeploymentまで辿れなかったのではないかと疑っている

おとうふおとうふ

エラーメッセージがわかりにくかったが、MachineDeploymentはちゃんと特定できていて、 https://github.com/kubernetes/autoscaler/blob/f87dbe5fc65ae6a6c550b0c22d7910ec192e7cfb/cluster-autoscaler/cloudprovider/clusterapi/clusterapi_nodegroup.go#L358 で引っかかっているだけだった。ちゃんと annotation (cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size) をMachineDeploymentにつけたら no node group config のログは消えた。

おとうふおとうふ

一方で、もともとやりたかったことを実現するにはreplicas=0のMachineDeploymentなどを用意してnodeを追加させたい(= scale from zero )わけだが、 これがサポートされるかどうかはprovider次第らしく、CAPVがどうかはわからなかった (issueなどを見る限り見当たらない)

おとうふおとうふ

https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20210310-opt-in-autoscaling-from-zero.md#implementation-detailsnotesconstraints を見るに、Infrastructure Machine Template (CAPVの場合VsphereMachineTemplate?) のstatusをprovider側でセットするか、MachineDeploymentとかのannotationをユーザー側でセットするかの2パターンがあるらしい。statusはセットされてないのでCAPVはおそらくscale from zeroをサポートしてないようだが、annotationの方法なら行けるはず…

だが、試しに設定してみた限りではうまく行かない。ログを見る限り使ってほしいMachineDeploymentに関するメッセージが何一つとして存在しない。

おとうふおとうふ

helm chart都合で1.26.2で試すことになったが、やはり依然としてうまく行かない

おとうふおとうふ

annotationでのリソース量の指定が悪かった。以下とかでパースされるので、そこでパース失敗しないようにしないといけない。

https://github.com/kubernetes/apimachinery/blob/v0.27.1/pkg/api/resource/quantity.go

(cluster-autoscalerを自前でビルドしてk8sクラスタ上に持っていくのも面倒だったが、配布されてるバイナリはストリップされていたのでデバッグがダルかった。GoReSymとかで処理が入っているか気になる関数のアドレスを特定→gdbをpodが動作するnodeで動かしてattachして問題箇所の候補にbreakpointを仕込んで通過しているか確認→怪しいところはdisassembleしてより細かく処理をみたい場所のアドレスを特定して、breakpointを設置…とやっていって、結局nodegroup内で作成されるnodeが提供するメモリ量を指定するannotationのパース処理でエラーになっているとわかった。パース失敗とかのエラーをcluster-autoscalerがちゃんとログに出してくれないのでわかりにくいというのもある…)

おとうふおとうふ

これでreplicas 0なMachineDeploymentをNode Groupとして認識してくれたっぽいが、nodeSelectorでnodeのlabelを指定しているUnschedulableなPod(条件を満たすNodeは存在しないが、追加したreplicas 0のMachineDeploymentがデプロイするnodeはその条件を満たすし、MachineDeploymentには capacity.cluster-autoscaler.kubernetes.io/labels のannotationを付けそれを指定している) に対して、対応しているNode Groupを見つけられないようで、

I0506 03:59:43.950589 1 scale_up.go:93] Pod testpod-769f847f9f-lknq9 can't be scheduled on MachineDeployment/ca-test/ca-test-md-1, predicate checking error: node(s) didn't match Pod's node affinity/selector; predicateName=NodeAffinity; reasons: node(s) didn't match Pod's node affinity/selector; debugInfo=

のようなログが出ている

おとうふおとうふ

https://github.com/kubernetes/autoscaler/blob/62d9c945786ff0a0b6942af269e8d5d05bee29fa/cluster-autoscaler/cloudprovider/clusterapi/clusterapi_utils.go#L38

MachineDeploymentへのannotationでnodeに付与するlabelを指定する(その値を用いてnodeSelector指定のあるPodをスケジュールできるかシミュレートする)機能は、 1.27.1 からの様子。

Helm chartとして対応するものはなかったが、 values.yaml 内の image.tag で1.27.1を指定して試したところ、ちゃんとMachineDeploymentのreplicasが書き換えられた!

おとうふおとうふ

label syncはCAPI 1.4以降で、1.3.3というやや古いののままだったので1.4.2に上げたら動くようになった。

ちゃんとnodeSelectorによってスケジュールできなかったPodが動かせるようになった