Skip to content
Published on

KubeVirtネットワーク1:PodネットワークをVMネットワークに変える基本原理

Authors

はじめに

ユーザーの立場で最も直感的な質問はこれだ。「VMはIPをどこから受け取るのか?CNIが直接VMにIPを与えるのか?」KubeVirtネットワークを理解するには、まず簡潔に答えられなければならない。

基本的にCNIはまずvirt-launcher Podにネットワークを与える。KubeVirtはそのPodのネットワークnamespace内でTAP、bridge、DHCP、NATを構成してゲストNICを接続する。

つまりゲストは通常CNIを直接呼び出さない。CNIが準備したPodネットワークをKubeVirtが再配線する。

なぜこの構造を選んだのか

KubeVirtの設計哲学はネットワークを新しく作るよりKubernetesとCNIを最大限再利用することだ。docs/components.mddocs/network/libvirt-pod-networking.mdはこれをかなり明確に説明する。

この構造を使うと:

  • Podスケジューリングとネットワークattachはそのままkubernetesが担い
  • KubeVirtはゲスト観点のNICワイヤリングだけ担当すればよく
  • Services、NetworkPolicy、Podネットワークエコシステムとの整合性が良くなる

つまりKubeVirtネットワークの核心は「VM専用ネットワークシステム」ではなくPodネットワークのguest-side adaptationだ。

最初に起こること:Podがネットワークを受け取る

virt-launcher Podが作成されるとまずCNIがPodネットワークを付ける。デフォルトのprimary interfaceは通常eth0として見える。この時点までは通常のPodと大きく変わらない。

重要なのはKubeVirtがまだゲストNICを作っていないという点だ。まずPodがネットワークを持ち、その後KubeVirtがこのネットワークnamespace内部でゲスト用構成を追加する。

pkg/network/setupがする仕事

核心コードはpkg/network/setup/network.gopodnic.gonetpod/*dhcp/*link/*に集まっている。

ここで見えるフローは次の通り。

  1. VMIのnetwork specとinterface specを読む。
  2. Podで実際のインターフェース名を見つける。
  3. バインディング方式に応じてbridge、masquerade、passt、SR-IOVなどのワイヤリングを決定する。
  4. 必要ならTAPデバイスを作りlibvirt domain NIC specを生成する。
  5. 必要ならKubeVirt内部DHCPサーバーを起動する。

つまりnetwork setupは「このVMのNICがゲストでどう見えるべきか」をPod namespace内で準備する段階だ。

TAPはなぜ必要なのか

ゲストOSは仮想NICを通じてパケットを送受信する。QEMU側では一般的にTAPデバイスをバックエンドとして使用する。cmd/virt-chroot/tap-device-maker.gopkg/network/setup/podnic.goを見るとKubeVirtがTAPデバイス作成を重要なプリミティブとして使用していることが分かる。

単純化すると:

  • Pod側インターフェースまたはbridgeがホスト側エンドポイント役
  • TAPがQEMU側エンドポイント役
  • libvirt domain specが両者を繋ぐ構成情報を含む

TAPはゲストとPodネットワークの間の実質的な接点の一つだ。

DHCPをなぜKubeVirtが直接起動するのか

多くの場合ゲストはCNIと直接対話しない。代わりにKubeVirtがゲストにネットワーク設定を教える。pkg/network/setup/podnic.goを見るとnewDHCPConfiguratorがbridgeまたはmasqueradeバインディングでDHCP configuratorを作り、EnsureDHCPServerStartedを呼び出す。

これはつまり:

  • Podインターフェース情報はホスト側にあり
  • ゲストが受け取るべきIPとgatewayはKubeVirtが計算して
  • DHCPでゲストに伝達する

ということだ。

ゲストIPは誰が割り当てるのか

ここでバインディング方式別に区別する必要がある。

masqueradeバインディング

pkg/network/dhcp/masquerade.gopkg/network/link/address.goを見ると、KubeVirtはゲスト用内部CIDRからgatewayとゲストIPを計算する。IPv4基準でVMNetworkCIDRがなければデフォルトCIDRを使い、そこからgatewayとゲストIPを決める。

つまりmasqueradeでは:

  • Pod IPは依然としてCNIがPodに割り当て
  • ゲストIPはKubeVirtが内部CIDRから計算
  • KubeVirt DHCPがゲストに伝達
  • egressとinboundの一部はNATで処理

これが最も一般的な「VMはprivate IPを受け取りPod IPの後ろに隠れている」モデルだ。

bridgeバインディング

bridgeバインディングはゲストをPodネットワークにより直接的に近く付ける。ここではbridgeとTAPを使ってゲストがPodネットワークのエンドポイントのように動作するようにする。bridgeバインディングの核心は「Pod IPをNATの後ろに隠す」ことよりもゲストをネットワークにより直接公開することにある。

masqueradeバインディングでNATはどう実装されるか

pkg/network/setup/netpod/masquerade/masquerade.goを見るとKubeVirtはmasqueradeでnftablesベースのNATルールを構成する。

重要なフロー:

  • NATテーブルとチェーン作成
  • ゲストソースアドレスに対するmasqueradeルール追加
  • ポートフォワーディングまたはDNATルール追加
  • loopbackとmigration関連例外ポート処理

つまりmasqueradeは単純に「ブリッジ一つ」ではなく:

  • 内部ゲストアドレス計算
  • DHCP
  • nftables NAT
  • 必要ポートのDNATまたはSNAT

が一緒に動作する組み合わせだ。

linkとinterface statusはなぜ重要か

KubeVirtはゲストNICがどのPod interfaceと接続されているか追跡しなければならない。そのためpkg/network/controllers/vmi.goはPod annotationのMultus network statusを読んでVMI statusのInterfacesフィールドを更新する。

このstatusには:

  • ゲスト側の論理ネットワーク名
  • Podインターフェース名
  • 情報ソースがPod statusかdomainかguest agentか

といった情報が入る。ネットワークデバッグでこれは非常に重要だ。

この構造が運用上もたらす利点

1. Kubernetesネットワークモデルを大きく壊さない

Podは依然としてCNIを通じてattachされる。

2. ゲスト設定を制御できる

KubeVirtがDHCPとbridgeまたはNATを直接扱うので、ゲスト側の体験を一貫させることができる。

3. バインディング別トレードオフを選択できる

パフォーマンス、到達性、サービス公開、migration適合性に応じてバインディングを選べる。

よくある誤解

誤解1:VMがCNIから直接IPを受け取る

基本的にはPodが先に受け取り、ゲストはKubeVirtがその上で接続する。

誤解2:Pod IPとゲストIPは常に同じだ

違う。特にmasqueradeでは両者は異なる。Pod IPはCNIが、ゲストIPはKubeVirt DHCPが扱う。

誤解3:KubeVirtネットワークはlibvirt内部機能だけで終わる

違う。Pod namespace操作、TAP、DHCP、nftables、netlinkが一緒に必要だ。

デバッグチェックリスト

  • Pod IPがあるかとゲストIPがあるかを分離して見る。
  • masqueradeならゲストCIDR、DHCP、nftablesルールを見る。
  • bridgeならPodインターフェースとbridge、TAP、ゲストDHCPパスを見る。
  • VMI statusのInterfacesとlauncher Podの実際のインターフェース名が一致するか見る。

まとめ

KubeVirtネットワークの核心はVMがCNIを直接使うのではなく、Podが先に受け取ったネットワークをゲスト親和的に再配線するところにある。だからIP割り当てもバインディングによって異なる。Pod IPはCNIが与えられるが、ゲストIPはKubeVirtのDHCPと内部bridgeまたはNATロジックが決定できる。この基本原理を掴んでおけば、次の記事でbridge、masquerade、passt、SR-IOVバインディングの違いをはるかに明確に理解できる。

次の記事ではまさにそのバインディングの性格とトレードオフを比較する。