TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

学生VMが立ち上がるまで2:KubeVirtの内部 — VMはなぜポッドの中で動くのか

ステータス:ドラフト(2026-10-16)、公式ドキュメント+一部実測。 コンポーネントの説明は、KubeVirtリポジトリのコンポーネントドキュメントとユーザーガイドを2026-10-16に確認しました。バージョンはKubeVirt v1.9.0です。「実測」と表示されている値はTT Labの実験用VMで測定したものです。作成ルール:実測データが基本であり、測定できなかったものは「未測定」、ドキュメントから見つからなかったものは「未確認」と表示します。

学生VMが立ち上がるまで2:KubeVirtの内部

目次

1編の⑥「VM → VMI → ポッド → QEMU」を開きます。

1. VirtualMachineとVirtualMachineInstance

KubeVirtを初めて見ると、似た名前の2つのオブジェクトで混乱します。

VirtualMachine (VM) VirtualMachineInstance (VMI)
意味 「このようなVMがあり、起動するかどうか」という希望する状態(Desired State) 今実際に稼働している1つの実行インスタンス
ライフサイクル 削除するまで残る VMを停止すると消え、起動すると新しく作成される
比喩 Deployment Pod

TT LabのバックエンドはVMのみを作成します。マニフェストに running: true を記述して作成と同時に起動させます。KubeVirtには同じ処理をより詳細に定義する runStrategy(Always・RerunOnFailure・Once・Manual・Halted)があり、両者は併用できません。コードのコメントには running が非推奨予定と記載されていましたが、ラン戦略ガイドではその文章が見つかりませんでした(未確認)。すでに稼働しているVMと動作を合わせるため、まだ変更していません。状態を確認する際はVMIを読み取ります。VMIがない場合は「起動中」、VMすらない場合は「削除済み」と判断します。

2. 4つのコンポーネント

VM 한 대 = 파드 하나 안의 QEMU 프로세스 컨트롤 플레인 kube-apiserver virt-api virt-controller 검증·기본값·서브리소스 객체를 보고 만든다 VM 켜 둘지 VMI 지금 도는 것 파드 virt-launcher 노드 (KVM 이 되는 곳) virt-handler 데몬셋 · 노드마다 VMI 를 켜고 끈다 kubelet 파드를 띄운다 virt-launcher 파드 virt-launcher (감시·신호 전달) libvirtd (도메인 관리) QEMU 프로세스 게스트 OS · systemd · root /dev/kvm 으로 하드웨어 가속 볼륨: 컨테이너 디스크 · emptyDisk PVC · cloud-init Secret 실측(2 vCPU · 4Gi VM): 파드 요청 CPU 200m · 메모리 4372Mi vCPU 하나에 CPU 0.1 개(할당 비율 기본 10), 메모리는 게스트 + 약 280Mi 파드라서 공짜로 얻는 것: 스케줄링 · 자원 요청 · 파드 네트워크 · 정책
図:1台のVMは1つのポッド内のQEMUプロセスである

KubeVirtリポジトリのコンポーネントドキュメントが説明している役割を要約すると以下の通りです。

作成手順はドキュメントに7つのステップとして記載されています。VMIが作成されるとvirt-controllerがポッドを作成し、スケジューラーがノードに配置し、ポッドが開始されるとvirt-controllerがVMIにノード名を書き込み、その時点からそのノードのvirt-handlerが引き継いでポッド内のlibvirtdにドメインを作成させます。第1編の実測(Pending 0秒 → Scheduled 10秒 → Running 20秒)はこの間を測定したものです。

3. なぜVMをポッド内に入れるのか

最初は奇妙に思えます。VMはコンテナよりも重い隔離機構なのに、なぜそれを再びコンテナの中に入れるのでしょうか。答えは「Kubernetesがすでに得意としていることを再実装しないため」です。TT Labで実際に恩恵を受けたものを挙げると以下の通りです。

  1. スケジューリングとリソース計算。 VMのCPU・メモリはポッドのリソース要求となり、スケジューラーがそのまま計算します。2 vCPU・4GiのVM 1つのポッド要求を測定したところ、CPU 200m、メモリ 4372Miでした(実測、2026-08-29)。1つのvCPUに対してCPU 0.1個分しか要求しないのは、KubeVirtの cpuAllocationRatio デフォルト値が10であるためであり(ユーザーガイド「Resources requests and limits」)、メモリはゲストの4Giに約280Miのオーバーヘッドが追加されました。
  2. ネットワークとポリシー。 ゲストはポッドのネットワークをそのまま使用します(masquerade)。そのため、実習用ポッドで使用していたネットワークポリシーをVMにも同じ方法で適用します。ポリシーが対象とするのはVMではなく virt-launcherポッドのラベルです。実際のネットワークエンドポイントがそのポッドであるためです(第6編)。
  3. ボリューム。 ゲストのディスクはポッドのボリュームです。PVCの接続、ノードローカルな一時ディレクトリの作成、Secretの挿入などはKubernetesが行います(第3・4編)。
  4. ライフサイクル。 ポッドが削除されるとVMも終了し、ポッドに付随する一時ボリュームも一緒に削除されます。クリーンアップが容易になります(第5編)。

代償もあります。

4. KVM:ハードウェアアクセラレーション

ゲストはQEMUがKVM(/dev/kvm)を使用してハードウェアアクセラレーションで動作します。KubeVirtはKVMが利用可能なノードにデバイスプラグインリソース(devices.kubevirt.io/kvm)を公開し、virt-launcherポッドがそのリソースを要求します。そのため、KVMが利用できないノードにはVMが配置されません。

ゲスト内でさらに仮想化を実行する必要がある実習(VM内でVMを起動する実習)では、CPUモデルを host-passthrough に変更します。デフォルトのCPUモデルはハードウェア仮想化フラグを隠すため、そのままだとゲスト内のQEMUがソフトウェアエミュレーションのみで動作し、起動に何分もかかります。 host-passthrough を有効にすると、ゲスト内に /dev/kvm が作成され、 lscpu に仮想化フラグが表示されました(実測、2026-08-29)。代償となるのは ライブマイグレーションです。ノードごとにCPUモデルが異なると移動できません。実習用VMはどうせ移動させないためこれを受け入れますが、不要な実習では有効化しません。

5. ゲスト内でコマンドを実行できない

ポッドには exec があるため、バックエンドはポッド内で採点コマンドを実行できます。KubeVirtのVMIサブリソースにはconsole、vnc、portforward、guestosinfoなどはあっても execはありません(実測によりサブリソースのリストを確認)。ゲストは独立したオペレーティングシステムであり、その中でコマンドを実行することは、ゲスト内に何らかのエージェントが存在する場合にのみ可能であるためです。

そのため、TT Labではゲストに小さな採点エージェントを埋め込みました(第1編 ③)。学生のシェルはシリアルコンソール(consoleサブリソース)で開きます。SSHを開く必要がないため、接続経路が1つ減ります。実際にプロトタイプでSSHを完全に無効にした状態でも採点が可能でした。

6. 実際に経験したこと:1つの機能ゲートでVMが全く立ち上がらなかった

KubeVirt v1.9.0を最初にインストールした際、VMが1つも立ち上がりませんでした。virt-launcherポッドが次のようなエラーで終了しました。

exec: "/container-disk-binary/usr/bin/container-disk": no such file or directory

コンテナランタイムの設定が壊れたのかと思いましたが、原因は別のところにありました。KubeVirt 1.9がベータ段階の機能ゲートをデフォルトで有効にしたことにより、 ImageVolume が自然と有効になりました。この機能はコンテナディスクをポッドのイメージボリュームとしてマウントしますが、 Kubernetes 1.34側ではそのゲートが無効になっていたため、APIサーバーがイメージボリュームとそのマウントを静かに削除しました。 ポッドは拒否されずに受け入れられるため、どこにも警告が残りません。実行中のポッドの仕様(Spec)からイメージボリュームが空になっているのを確認して初めて確信に至りました。コンテナランタイムも2つ目の関門でした。イメージボリュームをサポートするのはcontainerd 2.1以降であるため、Kubernetesのゲートを有効にしていたとしても、静的な削除がマウント失敗に置き換わるだけでした。

KubeVirt側のゲートを無効にして、以前の方式(空のディレクトリとコピー用initコンテナ)に戻しました。この設定はKubeVirtのカスタムリソースに含まれるため、 KubeVirtをアップデートするたびに再確認する必要が あります。記事を執筆している当日も、無効化されたゲートのリストに ImageVolume がそのまま残っていることを読み取って確認しました。

教訓は以下の通りです。「ポッド内のVM」は、Kubernetes、KubeVirt、コンテナランタイムという3つのバージョンの交点の上に成り立っています。1つだけアップデートすると、他の2つとの約束事が静かに破られることがあります。

7. 制限事項

ティティの一言。 VMをポッド内に入れるのは最初は「箱の中のさらに大きな箱」のように思えますが、おかげでスケジューリングもネットワークポリシーもボリュームもKubernetesが代わりにやってくれます。その代わり、3つのバージョンが連動して動いていることを必ず覚えておいてください。1つだけアップデートしたせいで、VMが静かに立ち上がらなくなることがありますよ!

参考

ドキュメントはすべて2026-10-16に閲覧しました。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます