Skip to content
Published on

ディスクとボリュームはどのようにVMに接続されるのか

Authors

はじめに

コンテナワークロードではボリュームがPodにマウントされれば仕事はほぼ終わりだ。しかしVMは違う。ゲストの立場では単純なファイルマウントではなく仮想ディスクデバイスが見えなければならない。したがってKubeVirtのストレージレイヤーはPodボリュームモデルとゲストディスクモデルの間を繋ぐ翻訳層になる。

この記事ではcontainer disk、PVC、DataVolume、hostDisk、generated volume、hotplug volumeがどのような経路でゲストに接続されるか見る。

最も重要な事実:ストレージは2回解釈される

KubeVirtでストレージは最低2段階を経る。

  1. KubernetesがPodレベルでボリュームソースを準備する。
  2. KubeVirtがこれをゲスト可視ディスクとして再解釈する。

つまり「PVCがlauncher Podに見える」と「ゲスト内にディスクが生まれる」は同じ文章ではない。

どのボリュームタイプがあるか

schema.goとconverter、ストレージ関連パッケージを見ると頻繁に登場するタイプは以下の通り。

  • PersistentVolumeClaim
  • DataVolume
  • ContainerDisk
  • HostDisk
  • CloudInitNoCloud
  • CloudInitConfigDrive
  • ConfigMap
  • Secret
  • ServiceAccount
  • hotplug volume

これらはゲスト観点ではすべて同じディスクではない。あるものは永続データ用、あるものはブートメタデータ用、あるものはmigration中のコピー対象ですらない。

container diskはなぜ特別なのか

cmd/virt-launcher/virt-launcher.gopkg/virt-handler/container-diskを見るとcontainer diskは専用ローカルディレクトリとmounterを通じて準備される。これはOSイメージ自体をコンテナイメージレイヤーのように配布しようとするKubeVirt特有のパターンだ。

利点は配布が簡単なこと。欠点は通常のPVCベースpersistentルートディスクとはライフサイクルが異なること。

つまりcontainer diskは「コンテナのように配信されるVMディスクイメージ」と見ればよい。

PVCとDataVolumeはどう扱われるか

PVC

PVCはKubernetesが既によく知っている永続ストレージモデルだ。KubeVirtはこれをPodに付けた後ゲストディスクとして接続する。

DataVolume

DataVolumeはCDIと接続されたhigher-level abstractionだ。通常イメージをimportまたはcloneした後、最終的にPVC形態のストレージを提供する。

virt-controllerがDataVolume準備状態も一緒に見る理由がここにある。ゲストディスクattachは結局Podにattach可能なストレージが準備されてこそ可能だからだ。

converterはボリュームソースをディスクソースに変える

前の記事で見たように、converterはvolumesdisksを結合する。この時ストレージ側で重要なのは実際のソースパスとモードを決定することだ。

例えば同じPVCでも:

  • filesystemベースならファイルパスを参照でき
  • blockモードならデバイスファイルのように扱わなければならない

この差はゲストディスクattach方式とmigration可能性にも影響する。

generated volumeはなぜ別扱いされるのか

live-migration-source.goclassifyVolumesForMigrationを見るとgenerated volumeという分類がある。ここには以下が含まれる。

  • config map
  • secret
  • downward API
  • service account
  • cloud-init
  • container disk

これらのボリュームは一般的なshared PVCとは異なり、ゲストブート補助情報または生成型データだ。migration時も同じ方式で扱ってはいけない。

つまりKubeVirtはディスクを単に「ストレージか否か」ではなく:

  • shared volume
  • generated volume
  • local volume to migrate

のようなより細かいクラスに分ける。

localディスクとsharedディスクの違いがなぜ重要なのか

live migration観点でこの違いは決定的だ。

sharedディスク

両方のノードが同じストレージを見れればディスク自体をコピーする必要がない。メモリ状態と実行状態だけ移せばよい。

localディスク

sourceノードにのみあるデータならmigration中にディスク内容も移さなければならない。この時block migrationまたはvolume migrationの問題が生じる。

live-migration-source.goはこのようなボリューム分類に基づいてどのディスクが実際のコピー対象かを計算する。

hotplug volumeはなぜもっと複雑なのか

通常のボリュームはVM開始前に準備すればよいが、hotplugは実行中のゲストに新しいディスクを入れる問題だ。

ここでは:

  • VMI spec変更検知
  • launcher Podまたはattachment Pod補助
  • ノードサイドマウント
  • libvirtデバイス追加

のような段階が連鎖的に必要だ。pkg/storage/hotplugpkg/virt-handler/hotplug-diskがこの領域の核心だ。

つまりhotplugはストレージ問題であると同時にランタイムデバイスアップデート問題だ。

virt-launcher初期化コードが示すストレージの現実

virt-launcher.goinitializeDirsは複数のディスクディレクトリを準備する。

  • cloud-init
  • ignition
  • container disk
  • hotplug disk
  • config map disk
  • secret disk
  • service account disk

このリストだけ見てもKubeVirtで「ディスク」という言葉が単純なブロックストレージよりはるかに広い意味を持つことが分かる。ゲストはこれらをそれぞれブートディスク、メタデータディスク、補助チャネル、追加ボリュームなどとして見ることになる。

migrationでストレージがなぜ常に問題の中心なのか

運用現場でmigration失敗原因のかなりの部分はネットワークやCPUよりもストレージ可視性の差から出る。

代表的な質問は以下の通りだ。

  • targetノードが同じPVCを見れるか
  • volume modeがblockかfilesystemか
  • generated volumeはtargetで再作成できるか
  • hotplugディスクがまだ整理されていないか

KubeVirtがmigration前にボリューム分類とtarget準備を細心に行う理由がまさにここにある。

よくある誤解

誤解1:Podにマウントされればゲストディスクも自動だ

違う。ゲストはlibvirt domainを通じてディスクデバイスを受け取らなければならない。

誤解2:PVCとDataVolumeはゲスト観点でほぼ同じだ

部分的には正しいが、準備過程と上位オーケストレーションは異なる。DataVolumeにはimportとcloneライフサイクルが追加される。

誤解3:すべてのディスクはmigration時に同じように処理される

違う。shared、generated、local-to-migrate分類が非常に重要だ。

運用者が最初に見るべきデバッグポイント

  • ゲストディスクが見えなければPodマウントとlibvirtディスクattachを分離して見る。
  • migration失敗ならsharedストレージ可視性とlocalボリューム有無を見る。
  • hotplug失敗ならspec反映、ノードマウント、libvirtデバイスアップデート順に見る。
  • cloud-initやsecretディスクの問題があればgenerated volume準備経路を見る。

まとめ

KubeVirtのストレージは「Podに付くボリューム」と「ゲストが見るディスク」の間の変換問題だ。PVCとDataVolumeは永続データ経路を、container diskとcloud-initはブート補助経路を、hotplugは実行中デバイス変更経路を担当する。そしてmigrationが入ると各ボリュームはshared、generated、local-to-migrateのようなより具体的な意味を持つようになる。

次の記事からはネットワークレイヤーに移り、PodネットワークをVMネットワークに変える基本原理から丁寧に見ていく。