kubeadm × ovn-kubernetesのクラスタでService CIDR問題にハマった
Table of Contents
はじめに
今回は、自宅サーバーで構築している kubeadm × ovn-kubernetes のKubernetesクラスタで、kubevirtを導入しようとした際に遭遇したService CIDRに関する問題とその解決方法についてお話しします!
kubeadm × ovn-kubernetesを構築した話はこちらの記事で紹介しているので、興味があればこちらもぜひ読んでみてください。
問題の発見
ovn-kubernetesで構築したKubernetesクラスタにkubevirtを導入しようとしたところ、virt-operatorで以下のようなエラーが出始めました。
Internal error occurred: failed calling webhook "virtualmachineclusterinstancetype-validator.instancetype.kubevirt.io": failed to call webhook: Post "https://virt-api.kubevirt.svc:443/virtualmachineclusterinstancetypes-validate?timeout=10s": context deadline exceeded
どうやらvirt-operatorがVirtualMachineClusterInstanceTypeリソースを作成しようとして、validation webhookがタイムアウトか何かで失敗しているようです。 validation webhookを叩くのはkube-apiserverだと思ったので、kube-apiserver側のログも確認してみました。
kube-apiserver-home-k8s-master01 kube-apiserver W0902 13:48:03.160803 1 dispatcher.go:217] Failed calling webhook, failing closed virtualmachineclusterinstancetype-validator.instancetype.kubevirt.io: failed calling webhook "virtualmachineclusterinstancetype-validator.instancetype.kubevirt.io": failed to call webhook: Post "https://virt-api.kubevirt.svc:443/virtualmachineclusterinstancetypes-validate?timeout=10s": context deadline exceeded
やはりリソース作成のリクエストを受けたkube-apiserver側でvalidation webhookを叩くのに失敗していそうでした。
原因調査と解決方法
通信テストと原因の絞り込み
普通にvirt-apiのServiceのドメインにアクセスしているように見えるのに、なぜアクセスできないのでしょうか?
まずはkube-apiserverと同じkube-system namespaceにPodを作成してアクセステストをしてみました。
# curl -vk https://kubevirt-operator-webhook.kubevirt.svc:443/kubevirt-validate-update
...
< HTTP/1.1 400 Bad Request
< Date: Tue, 02 Sep 2025 13:51:54 GMT
< Content-Length: 0
<
* Connection #0 to host kubevirt-operator-webhook.kubevirt.svc left intact
400ですが普通にアクセスできていそうです。kube-apiserver Podと何が違うんでしょうか?
改めてkube-apiserver Podのspecを確認するとhostNetwork: true
になっていました。これは怪しそうです。
試しに hostNetwork: true
のPodを作成して再度試してみると、案の定アクセスできませんでした。
root@home-k8s-worker02:/# getent hosts virt-api.kubevirt.svc
10.108.245.218 virt-api.kubevirt.svc.cluster.local
root@home-k8s-worker02:/# curl --connect-timeout 3 https://virt-api.kubevirt.svc:443/virtualmachineclusterinstancetypes-validate
curl: (28) Failed to connect to virt-api.kubevirt.svc port 443 after 3002 ms: Timeout was reached
アドレスは引けているのにアクセスできません。
ルーティングテーブルの調査
hostNetwork: true
がダメだということはNodeのネットワーク設定が悪そうなので、Nodeのルーティングテーブルを確認してみました。
ubuntu@home-k8s-master01:~$ ip r
default via 192.168.1.1 dev breth0 proto static
10.96.0.0/16 via 169.254.0.4 dev breth0 src 169.254.0.2 mtu 1400
10.244.0.0/24 dev ovn-k8s-mp0 proto kernel scope link src 10.244.0.2
10.244.0.0/16 via 10.244.0.1 dev ovn-k8s-mp0
169.254.0.0/17 dev breth0 proto kernel scope link src 169.254.0.2
169.254.0.1 dev breth0 src 192.168.1.101
169.254.0.3 via 10.244.0.1 dev ovn-k8s-mp0
192.168.1.0/24 dev breth0 proto kernel scope link src 192.168.1.101
一見普通ですが、よくよく見てみると怪しいところがありました。
10.96.0.0/16 via 169.254.0.4 dev breth0 src 169.254.0.2 mtu 1400
10.244.0.0/24 dev ovn-k8s-mp0 proto kernel scope link src 10.244.0.2
10.244.0.0/16 via 10.244.0.1 dev ovn-k8s-mp0
これらはそれぞれService network、Pod network(Node/クラスタ全体)宛てのルートっぽいですが、Service networkのCIDRが 10.96.0.0/16
になっています。
確かkubeadmのデフォルトService networkは 10.96.0.0/12
だったような気がしますが…
根本原因の特定
実際にServiceのアドレスを確認してみると:
$ k get svc -n kubevirt -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubevirt-operator-webhook ClusterIP 10.111.35.104 <none> 443/TCP 3d1h kubevirt.io=virt-operator
kubevirt-prometheus-metrics ClusterIP None <none> 443/TCP 3d1h prometheus.kubevirt.io=true
virt-api ClusterIP 10.108.245.218 <none> 443/TCP 3d1h kubevirt.io=virt-api
virt-exportproxy ClusterIP 10.106.110.67 <none> 443/TCP 3d1h kubevirt.io=virt-exportproxy
やっぱりServiceのアドレスが 10.96.0.0/16
の範囲に収まっていないようです。
kubeadmの公式ドキュメントを確認すると:
–service-cidr string Default: “10.96.0.0/12”
Use alternative range of IP address for service VIPs.
やっぱりそうでした!
宛先のvirt-api Serviceのアドレスが 10.108.245.218
で、10.96.0.0/16
のルートにマッチしないために通信できていないようです。
解決方法
kubeadmのデフォルトService CIDRが 10.96.0.0/12
なのに対し、ovn-kubernetesが 10.96.0.0/16
でルートを設定していたことが原因でした。
そこで、kubeadm init
時にクラスタのService CIDRを明示的に 10.96.0.0/16
に指定することにしました。
kubeadm init \
...
--pod-network-cidr 10.244.0.0/16
--service-cidr 10.96.0.0/16
解決後の確認
修正後、Serviceのアドレスが指定したCIDRに入っていることを確認しました:
$ k get svc -n kubevirt -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubevirt-operator-webhook ClusterIP 10.96.224.153 <none> 443/TCP 72s kubevirt.io=virt-operator
kubevirt-prometheus-metrics ClusterIP None <none> 443/TCP 72s prometheus.kubevirt.io=true
virt-api ClusterIP 10.96.195.9 <none> 443/TCP 72s kubevirt.io=virt-api
virt-exportproxy ClusterIP 10.96.139.38 <none> 443/TCP 72s kubevirt.io=virt-exportproxy
そして無事にvalidation webhookを叩けるようになり、kubevirtのデプロイができました!
$ kubectl get kubevirt.kubevirt.io/kubevirt -n kubevirt -o=jsonpath="{.status.phase}"
Deployed
まとめ
今回の問題は、kubeadmとovn-kubernetesのデフォルト設定の微妙な不整合が原因でした。 あんまりkubeadmでovn-kubernetesを使ってる人いないんですかね…?
マイナーなアドオンやプラグインを使う場合は、こういう変なところでつまづくことがありますが、それがまたトラブルシューティングの面白さでもありますね! kubernetes本体(kube-apiserverなど)やネットワークアドオンの設定について理解が深まってよかったです。
最後まで読んでいただき、ありがとうございました。