なぜKubernetesで仮想マシンを実行するのか?
多くの自宅ラボ(HomeLab)愛好家は、PlexのようなメディアサーバーやシンプルなWebアプリをホストするために、Dockerや軽量なKubernetesクラスターから使い始めます。しかし、やがて壁に突き当たります。特殊なネットワークアプライアンスや、コンテナ化を拒むレガシーなWindowsアプリ、あるいは特定のLinuxカーネルバージョンが必要になることがあるからです。通常、このような場合はProxmoxやESXiといった別のハイパーバイザーを別途維持管理する必要があります。
2つの異なるコントロールプレーンを使い分けることは、設定の不整合(構成ドリフト)や精神的な疲労の原因になります。私は、すべてを単一のAPIで管理する方法を求めていました。KubeVirtはKubernetesを拡張することでこのギャップを埋め、他のPodと同じように仮想マシン(VM)をスケジュールし、管理できるようにします。私はこの構成を1年以上運用してレガシーなビルドサーバーをホストしていますが、管理の手間を半分に減らしつつ、非常に堅牢な安定性を維持しています。
KubeVirtアプローチのメリット
- 統合されたネットワーキング: VMを標準のKubernetes ServiceやIngressの背後に配置できます。つまり、Windows VMウェもWebコンテナと同じTraefikやNginxロードバランサーの恩恵を受けられるということです。
- 宣言的な管理: VMをYAMLファイルで定義できます。インフラ全体をGitでバージョン管理し、
kubectl applyだけでデプロイ可能です。 - リソースの効率化: 専用のハイパーバイザーOSを必要としません。ノードに空きRAMがあれば、そこでVMを実行できます。私のテストでは、KubeVirtランチャーPodのオーバーヘッドはごくわずかで、通常は100MB未満のRAM消費です。
インストール:クラスターの準備
YAMLを記述する前に、ハードウェアが仮想化をサポートしているか確認してください。KubeVirtはPod内でKVMを実行します。Kubernetesノード自体が仮想マシンである場合(入れ子になった仮想化:ネストされた仮想化)、まず基盤となるハイパーバイザーでその機能を有効にする必要があります。
ステップ 1: ハードウェア仮想化の確認
ノードで次のコマンドを実行し、VMX(Intel)またはSVM(AMD)拡張機能が有効かどうかを確認します。
grep -E 'vmx|svm' /proc/cpuinfo
出力が空の場合は、BIOS設定を確認してください。Raspberry PiのようなARMボードで実行する場合、KubeVirtはソフトウェアエミュレーションを使用できます。ただし、ハードウェアアクセラレーションによる仮想化よりも10倍近く遅くなることが多いため、注意が必要です。
ステップ 2: KubeVirt Operatorのデプロイ
KubeVirtは、自身のライフサイクルを管理するためにOperatorパターンを使用します。これにより、必要なカスタムリソース定義(CRD)のインストールといった重労働が処理されます。互換性を確保するため、常に公式リリースから最新のバージョン文字列を取得してください。
# 最新バージョンを取得
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
# Operatorをデプロイ
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml
# KubeVirtカスタムリソースをデプロイ
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml
ステップ 3: virtctlのインストール
標準のkubectlコマンドでも基本的なタスクは行えますが、より詳細な制御にはvirtctlバイナリが必要になります。これはVNCコンソール、VMの起動/停止、イメージのアップロードなどを処理します。20MB程度のダウンロードで、運用が大幅に楽になります。
VERSION=$(curl -s https://api.github.com/repos/kubevirt/kubevirt/releases/latest | grep tag_name | cut -d '"' -f 4)
curl -L -o virtctl https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/virtctl-${VERSION}-linux-amd64
chmod +x virtctl
sudo install virtctl /usr/local/bin/virtctl
設定:ストレージとイメージ
数ギガバイトのISOやQCOW2イメージをクラスターに取り込む作業は、通常このプロセスで最も困難な部分です。KubeVirtはContainerized Data Importer (CDI) を使用してこれを自動化します。CDIは、HTTPサーバーやS3バケットから直接イメージをプルし、Persistent Volumeに書き込むことができます。
CDIのインストール
export VERSION=$(curl -s https://api.github.com/repos/kubevirt/containerized-data-importer/releases/latest | grep tag_name | cut -d '"' -f 4)
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/${VERSION}/cdi-operator.yaml
kubectl create -f https://github.com/kubevirt/containerized-data-importer/releases/download/${VERSION}/cdi-cr.yaml
最初の仮想マシンの作成
CDIが起動したら、VMを定義できます。この例ではFedora Cloudイメージを使用します。DataVolumeセクションは、CDIに400MBのイメージを取得させ、10GBのディスクを自動的に準備するよう指示します。
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: fedora-vm
spec:
running: false
template:
spec:
domain:
devices:
disks:
- disk: {bus: virtio}
name: datavolumedisk
resources:
requests:
memory: 2Gi
volumes:
- dataVolume:
name: fedora-dv
name: datavolumedisk
dataVolumeTemplates:
- metadata:
name: fedora-dv
spec:
storage:
resources:
requests:
storage: 10Gi
storageClassName: local-path
source:
http:
url: "https://download.fedoraproject.org/pub/fedora/linux/releases/38/Cloud/x86_64/images/Fedora-Cloud-Base-38-1.6.x86_64.qcow2"
マニフェストを適用すると、「importer」Podが起動します。ギガビット接続であれば、VMの起動準備が整うまで、イメージのダウンロードと検証に通常約45秒かかります。
検証とモニタリング
私は通常、最初のYAMLでrunning: falseを設定します。これにより、イメージのダウンロード中にVMが起動しようとするのを防げます。PVCのステータスが「Bound」になったら、準備完了です。
VMの起動
新しいCLIツールを使用してマシンを起動します:
virtctl start fedora-vm
コンソールへのアクセス
KubeVirtのターミナル統合は非常に優れています。IPアドレスを探したりSSHを設定したりすることなく、シリアルコンソールに直接入ることができます:
virtctl console fedora-vm
Windows VMやLinuxデスクトップの場合は、VNCトンネルを使用します。次のコマンドはローカルポートを開き、デフォルトのVNCビューアを起動します:virtctl vnc fedora-vm。
現場からの重要なポイント
- VirtIOを優先する: 常に
bus: virtioを使用してください。私のベンチマークでは、VirtIOドライバーはエミュレートされたSATAと比較して最大3倍高速なディスクI/Oを提供します。 - Cloud-Initで自動化する: ユーザーを手動で作成して時間を無駄にしないでください。
cloudInitNoCloudを使用して、最初の起動時にSSH公開鍵やネットワーク設定を注入しましょう。 - 高度なネットワーキング: VMに(10.x.x.xのクラスターIPではなく)自宅のVLAN上の実際のIPを持たせたい場合は、Multus CNIを検討してください。これにより、VMを物理ネットワークインターフェースに直接ブリッジできます。
KubeVirtをセットアップすることで、Kubernetesクラスターは真のプライベートクラウドへと進化します。YAMLベースのVM管理には多少の学習曲線がありますが、スタック全体を一箇所で管理できるメリットは、あらゆる自宅ラボにとって大きなアップグレードとなるはずです。

