はじめに
KubeVirtの構造を辿ると最初に出会うタイプが`VirtualMachine`、`VirtualMachineInstance`、`VirtualMachineInstanceMigration`だ。名前が似ているため最初は混乱するが、この3つのオブジェクトを区別できなければ、その後のcontroller、migration、状態追跡ロジックもすべてぼやけてしまう。
この記事は`staging/src/kubevirt.io/api/core/v1/types.go`と`schema.go`を中心に、各オブジェクトが**意図**、**実行中インスタンス**、**一回限りの移動リクエスト**のどれを表すのか整理する。
なぜオブジェクトを3つに分けるのか
Kubernetesの基本パターンを思い出せば理解しやすい。
- Deploymentは「望ましい状態」を表現する。
- Podは「現在実行中のインスタンス」を表現する。
- Jobは「一度実行する作業」を表現する。
KubeVirtも同様の分離を採用する。
- `VirtualMachine`:長期的なVM意図と運用ポリシー
- `VirtualMachineInstance`:今生きているゲストインスタンス
- `VirtualMachineInstanceMigration`:特定のVMIを別のノードに移すための作業オブジェクト
この分離があるからこそ、start、stop、restart、migration、eviction、ステータス反映が互いに絡まない。
`VirtualMachine`は「持続的な意図」だ
`VirtualMachine`は「このVMをどのような形で維持したいか」を表現する上位オブジェクトだ。ユーザーは通常ここにtemplate、run strategy、data volume接続ポリシーを宣言する。
核心ポイントは`VirtualMachine`がゲストプロセスそのものを意味するわけではないという点だ。実際の実行主体は`VirtualMachineInstance`だ。
`VirtualMachine`が有用な場面
- VMをオフにしてオンにしても同じ意図を維持したい場合
- 運用ポリシーを状態と分離したい場合
- startまたはstopリクエストを宣言的に管理したい場合
つまり`VirtualMachine`は「このVMは存在すべきか」を扱い、`VirtualMachineInstance`は「今現在どこでどのように実行中か」を扱う。
`VirtualMachineInstance`は実行中ゲストの実体だ
`VirtualMachineInstance`、略してVMIはKubeVirtの核心ランタイムオブジェクトだ。`types.go`でこのオブジェクトはspecとstatusを併せ持つruntime definitionとして説明される。
実際にcontrollerとnode agentが最も頻繁に観察するオブジェクトもVMIだ。理由は簡単だ。Pod作成、ノード割り当て、ネットワークステータス、migration状態、guest agent情報などの**実行中状態の中心**がVMIだからだ。
VMI specの重要なフィールド
- `domain`:CPU、メモリ、ディスク、NICなどのゲストハードウェア要件
- `nodeSelector`、`affinity`、`tolerations`:どのノードに行けるか
- `volumes`:どのストレージをゲストに接続するか
- `networks`:どのネットワークをゲストNICに接続するか
- `terminationGracePeriodSeconds`:終了シグナルと強制終了の間の猶予時間
つまりVMI specは「このゲストを今実行するためにランタイムは何を準備すべきか」を示す。
VMI statusはなぜこんなに多いのか
`VirtualMachineInstanceStatus`は思ったより豊富だ。これが重要な理由は、KubeVirtが単一のモノリシックデーモンではなく、複数のcontrollerとnodeコンポーネントがコレオグラフィ方式で協力するからだ。各コンポーネントはstatusを見て次の行動を決定する。
代表的に重要なフィールドは以下の通り。
- `NodeName`:現在VMIがどのノードで実行中か
- `Phase`:Pending、Scheduling、Runningなどの上位状態
- `Conditions`:paused、agent connected、migratableなどの詳細フラグ
- `Interfaces`:ゲストとPodインターフェースのマッピング状態
- `MigrationState`:migration進行状況
- `MigrationMethod`:live migrationかblock migrationか
- `MigrationTransport`:どのtransportを使用するか
- `ActivePods`:一つのVMIに対してどのlauncher Podが生きているか
特に`ActivePods`はmigration時に重要だ。通常はVM一台にPod一つのように見えるが、migration中はsource Podとtarget Podが一時的に共存できる。
`VirtualMachineInstanceMigration`は「作業リクエスト」だ
多くのユーザーがmigrationをVMI status内のボタンのように考えるが、KubeVirtは別のCRDを使用する。`VirtualMachineInstanceMigration`オブジェクトを作成するとcontrollerがそれを見てmigration orchestrationを開始する。
この設計の利点は明確だ。
- migrationを監査可能な独立オブジェクトとして追跡できる
- ポリシー適用が容易になる
- 状態遷移を別のライフサイクルとしてモデリングできる
- 失敗理由を作業単位で残せる
`pkg/virt-api/rest/lifecycle.go`のmigrate handlerを見ると、実際にmigrateリクエストは内部で`VirtualMachineInstanceMigration`オブジェクト作成に変換される。つまりユーザーの「migrate」ボタンクリックは結局「migration CR作成」に変わる。
オブジェクト関係を一つの図で理解する
VirtualMachine
-> template/spec/policyを持つ長期オブジェクト
-> 実行が必要な時にVMIを誘導
VirtualMachineInstance
-> 現在実行中のゲストインスタンス
-> Pod、ノード、ネットワーク、ストレージ、migration状態の中心
VirtualMachineInstanceMigration
-> 特定VMIを移すための一回限りの作業オブジェクト
-> controllerがtarget Pod作成とhandoffを開始
この構造は「desired state」、「runtime instance」、「operation request」を混ぜないようにする意図と理解すればよい。
`schema.go`に見える設計哲学
`schema.go`を見るとVMI spec内にネットワークとボリューム、CPU、memory、firmware、launch security、access credentialsなどのフィールドが非常に豊富に定義されている。これはKubeVirtが単純に「QEMU実行ラッパー」ではなく、**ゲストハードウェアと運用環境をKubernetes API形式で宣言可能にした層**であるということを意味する。
逆にstatus側はオーケストレーション親和的に設計されている。例えばネットワークインターフェースstatus、ゲストOS情報、migration stateはゲスト内部情報とクラスタオーケストレーション状態を共に含む。この点がコンテナPod statusとは異なる質感だ。
なぜVMとVMIを統合しなかったのか
この質問は重要だ。もし一つのオブジェクトにすべて入れたら、実装は単純に見えるかもしれない。しかし実際の運用では以下の問題が生じる。
1. オフにしてオンにしても同じ「意図」を維持しにくい
実行中のインスタンス状態とユーザーの永続的設定が一つのオブジェクトに混ざるとライフサイクルが複雑になる。
2. status churnが大きくなりすぎる
ランタイム状態は頻繁に変わるが、意図は頻繁には変わらない。両者を分離してこそwatch コストとreconcile責任が整理される。
3. migrationのような作業をモデリングしにくい
別の作業オブジェクトがあってこそ、ポリシー、キューイング、優先順位、失敗理由をきれいに扱える。
運用者がstatusで最初に見るべきもの
実務ではこの3つのオブジェクトすべてを見るが、状況ごとに優先順位が異なる。
VMが起動しない場合
- `VirtualMachine`のrun strategy
- VMIが作成されたか
- VMI phaseがどこまで進んだか
ネットワークやブートがおかしい場合
- VMI statusの`Interfaces`
- `Conditions`
- `ActivePods`
migrationが問題の場合
- `VirtualMachineInstanceMigration` status
- VMI statusの`MigrationState`
- source Podとtarget Podの状態
よくある誤解
誤解1:VMとVMIは名前が違うだけで実質同じだ
違う。一つは意図、一つはランタイム実体だ。この違いを理解してこそstart/stop、restart、migration、drainロジックが見える。
誤解2:migrationはVMIフィールドを一つ変えるだけで始まる
違う。別のmigration CRが作成され、controllerがそのオブジェクトを作業単位として消費する。
誤解3:statusは単なるUI用途だ
違う。KubeVirt内部コンポーネント同士が協力するための重要な契約面だ。
まとめ
KubeVirtのオブジェクトモデルは偶然複雑なのではない。`VirtualMachine`は持続的な意図、`VirtualMachineInstance`は実行中のインスタンス、`VirtualMachineInstanceMigration`は一回限りの移動リクエストを表現する。この分離があるからこそKubeVirtはKubernetesスタイルの宣言的APIを維持しながらも、VM実行や移動のように状態が多い作業を安定的に処理できる。
次の記事では、これらのオブジェクトが実際のAPI進入点でどのように扱われるか、そして`virt-api`がどのような検証とsubresource動作を行うかを見ていく。
현재 단락 (1/74)
KubeVirtの構造を辿ると最初に出会うタイプが`VirtualMachine`、`VirtualMachineInstance`、`VirtualMachineInstanceMigration`...