- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- 1. KVM:なぜVMが「高速に」動くのか
- 2. namespace:なぜPodがVM実行サンドボックスになれるのか
- 3. cgroup:VMもホストリソース制約を受けなければならない
- 4. TAP:ゲストNICとホストネットワークをつなぐ重要なデバイス
- 5. netlink:ネットワークは結局カーネルオブジェクト操作である
- 6. nftables:masqueradeバインディングの実際のデータプレーン
- 7. VFIO:SR-IOVとデバイスパススルーの基盤
- 8. seccompとデバイス許可リストもカーネルの問題
- なぜKubernetesだけではこの作業ができないのか
- よくある誤解
- 運用者が覚えるべき要点
- まとめ
はじめに
KubeVirtを深く理解するには、Goコントローラコードだけ読んでいては不十分である。結局このシステムが可能になる理由は、Linuxカーネルとホストランタイムが提供するプリミティブのおかげである。KubeVirtは新しいハイパーバイザーを作ったのではなく、既存のカーネル機能とQEMU、libvirtをKubernetesリソースモデルに組み込むシステムである。
本記事ではその基盤となるカーネル技術を整理する。
1. KVM:なぜVMが「高速に」動くのか
最も重要なのは/dev/kvmである。pkg/virt-handler/node-labeller/util/util.goはそもそもKVMPath = "/dev/kvm"を定数として定義している。これはKubeVirtがハードウェア仮想化アクセラレーションの可否を非常に重視していることを意味する。
QEMUだけでもエミュレーションは可能だが、パフォーマンスは大きく低下する可能性がある。KVMはゲストの多くのCPU実行パスをハードウェア仮想化に委ねてパフォーマンスを向上させる。
つまりKubeVirtが本番VMプラットフォームとして動作するには、結局/dev/kvmへのアクセスが可能でなければならない。
2. namespace:なぜPodがVM実行サンドボックスになれるのか
Podは単なるデプロイメントの束ではなく、namespaceの集合である。
- ネットワークnamespace
- マウントnamespace
- PID namespace
QEMUは結局Linuxプロセスである。したがってこのnamespace境界の中で実行できる。これが「VMがPod上で動く」という言葉の最も現実的な意味である。
KubeVirtのvirt-chroot系コードを見ると、特定のマウントnamespaceに入ってマウントやSELinux操作を行う機能がある。つまりKubeVirtはnamespaceを抽象的な概念ではなく、実際の運用ツールとして積極的に使っている。
3. cgroup:VMもホストリソース制約を受けなければならない
VMだからといってホストリソース制約の外にいてはいけない。QEMUと関連スレッドも結局Linuxプロセスなのでcgroup制約を受ける必要がある。
cmd/virt-chroot/cgroup.go、pkg/virt-handler/cgroup/*、vm.goを見ると、KubeVirtがcgroup v1とv2の違い、デバイス許可リスト、cpuset、ブロックデバイスルールまで気を配っていることがわかる。
つまりKubeVirtは「Podリクエスト」レベルで終わらず、実際のVM実行プロセスに正確なcgroupリソース制約を適用しようとしている。
4. TAP:ゲストNICとホストネットワークをつなぐ重要なデバイス
TAPデバイスはゲストが見る仮想NICとホストまたはPod側ネットワークを接続する代表的なバックエンドである。cmd/virt-chroot/tap-device-maker.goとpkg/network/setup/podnic.goがこれをよく示している。
ゲストの観点からはvirtio-netのような仮想NICが見えるが、ホスト側では結局TAPデバイスとブリッジ、NATルールがパケットを接続する。
つまりTAPはゲストとPod namespaceネットワーク間の実質的なゲートウェイである。
5. netlink:ネットワークは結局カーネルオブジェクト操作である
KubeVirtのネットワークコードがnetlinkを多用する理由は、ブリッジ、アドレス、リンク状態、TAP、MTU設定がすべてカーネルネットワークオブジェクトだからである。
例えば:
- TAP作成
- MTU設定
- ブリッジアドレス計算
- masqueradeゲートウェイとゲストIP計算
これらの操作は単純なファイル編集ではなく、カーネルネットワーク状態の操作である。
つまりKubeVirtのネットワーキングは「YAML から CNI」だけの問題ではなく、namespace内部のLinuxネットワークスタック操作である。
6. nftables:masqueradeバインディングの実際のデータプレーン
pkg/network/setup/netpod/masquerade/masquerade.goはmasqueradeバインディングでnftablesルールを構成する。これは重要なポイントである。
多くのユーザーがNATを抽象的に考えるが、実際には:
- NATテーブル
- prerouting
- postrouting
- dnat
- snat
- masquerade
のルールがカーネルパケットパスに入る。
つまりKubeVirtのゲストegressと一部のinboundモデルはユーザースペースの魔法ではなく、カーネルパケットフィルタリングとNAT機能の上に立っている。
7. VFIO:SR-IOVとデバイスパススルーの基盤
docs/network/sriov.mdとvirtwrap/device/hostdevice系コードを見ると、SR-IOVとデバイスパススルーはVFIOモデルに依存している。ゲストにデバイスを直接渡すには、ホストカーネルがデバイスを安全にユーザースペースハイパーバイザーに委任できる必要がある。
そのためSR-IOVは単純なネットワーク機能ではなく、以下が全て揃う必要のあるカーネルとハードウェア機能のセットである。
- IOMMU
- VFIO
- デバイスプラグイン
- libvirt hostdev設定
8. seccompとデバイス許可リストもカーネルの問題
virt-handlerはseccompプロファイルもインストールする。またhotplugブロックデバイスパスではcgroupデバイスルールを調整する。これは「QEMUは単純なprivilegedプロセスだから何でもできる」ではなく、必要なsyscallとデバイスアクセスのみ許可する方向でシステムを設計したことを意味する。
つまりカーネルプリミティブはパフォーマンスだけでなくセキュリティ境界においても重要である。
なぜKubernetesだけではこの作業ができないのか
KubernetesはPodを配置し、ボリュームとネットワークを準備してくれる。しかし:
/dev/kvmをどう使うか- TAPをどう作るか
- libvirtとQEMUをどう接続するか
- ゲストメモリとデバイス状態をどう移すか
といった仮想化固有の問題は直接解決しない。KubeVirtはまさにこのギャップを埋める。ただし基盤は依然としてLinuxカーネル機能である。
よくある誤解
誤解1:KubeVirtはKubernetes内部に仮想化エンジンを追加する
いいえ。仮想化エンジン自体はKVMとQEMU、libvirtである。KubeVirtはこれをKubernetesと統合する。
誤解2:Pod上で動くならカーネル技術はあまり重要ではない
逆である。Podという包み紙を使っても、実際の実行はカーネルnamespace、cgroup、KVM、netlink、nftablesの上で行われる。
誤解3:ネットワークとデバイスは大部分がユーザースペースロジックである
いいえ。重要な部分は常にカーネルオブジェクトとカーネルポリシーに触れている。
運用者が覚えるべき要点
- VMの問題はKubernetesの問題ではなくホストカーネルの問題であることが多い。
/dev/kvm、cpuset、cgroupデバイスルール、TAP、nftablesの状態を一緒に見る必要がある。- SR-IOVとVFIOはハードウェア、BIOS、カーネル、CNI、libvirtがすべて揃う必要がある。
まとめ
KubeVirtがPod上でVMを実装できる理由は、Kubernetesがすべてをやってくれるからではなく、Linuxカーネルがすでに強力な仮想化と分離のプリミティブを提供しているからである。KVMはCPUアクセラレーションを、namespaceとcgroupは実行境界を、TAPとnetlinkはゲストネットワーク接続を、nftablesはNATを、VFIOはデバイスパススルーを可能にする。KubeVirtはまさにこれらのプリミティブをKubernetesリソースモデルの上で組み合わせるシステムである。
次の記事では、このカーネル境界の上に置かれたセキュリティ境界、すなわちSELinux、seccomp、デバイスアクセスに関するKubeVirtのセキュリティモデルを見ていく。