仮想マシン内でさらに仮想マシンが起動しない問題
Proxmox VEの3ノードクラスタ構築の練習や、VMware ESXiの検証、OpenStack DevStackの検証環境を用意する場合、複数の物理サーバーがあるのが理想的です。しかし現実には、自宅にベアメタルサーバーを何台も並べる予算や設置スペースを確保できる人は多くありません。
最も一般的な解決策は、標準的なスペックのLinuxマシン(8コア、32GB RAM程度)や外部のKVMレンタルサーバーを活用することです。第1階層の仮想マシン(L1ゲスト)を作成し、そこにProxmoxやESXiをインストールします。しかし、その内部で第2階層の仮想マシン(L2ゲスト)を起動しようとした瞬間にトラブルが発生します。
TASK ERROR: KVM acceleration not available, using software emulation
# またはVMware ESXiのエラーメッセージ:
Hardware Virtualization is not a feature of the CPU, or is not enabled in the BIOS
この状態での使用感は非常に劣悪です。仮想マシンはソフトウェアエミュレーション(TCG)で動作するため、ホストのCPU使用率が100%に跳ね上がり、Ubuntu Serverの起動だけに15〜20分もかかったり、ESXiのインストーラーによってセットアップ自体がブロックされたりします。
筆者のホームラボ(Ryzen 7 5700X、64GB RAM)でも、HA(高可用性)機能やCephストレージの検証クラスタはすべてネストされたVMとして稼働させています。以前、ホスト側で仮想化フラグを有効化し忘れていただけで一晩潰してしまった経験があります。
なぜL1仮想マシンは仮想化命令セットを認識できないのか?
入れ子型仮想化(Nested Virtualization)のアーキテクチャは、大きく3つの階層に分かれています。
- L0(ベアメタルホスト): Linuxを実行し、KVMモジュールをロードしている物理サーバー。
- L1(ゲストハイパーバイザー): L0上で動作し、中間ハイパーバイザーとして機能する仮想マシン(Proxmox、ESXiなど)。
- L2(ネストされたゲスト): L1の内部で動作する仮想マシン。
Intel製CPUにはVMX(VT-x)、AMD製CPUにはSVM(AMD-V)という命令セットが存在します。L0層のハイパーバイザーはこれらの命令セットを利用して、仮想マシンにハードウェアリソースを直接割り当てます。
RHELやDebianをはじめとする多くのLinuxディストリビューションでは、メモリ保護や安全性の観点から、kvm_intelやkvm_amdモジュール内の入れ子仮想化フラグがデフォルトで無効になっています。そのため、L0ホストはこれらのハードウェアフラグを隠蔽し、L1へパススルーしません。
さらに、libvirt経由でL1仮想マシンを作成する際、CPUモデルがデフォルトのqemu64になっていると、基本的なx86命令セットしか提供されません。L1仮想マシンからはVT-x/AMD-Vフラグが完全に削ぎ落とされるため、ハードウェア支援機能が使えず、L1上でL2仮想マシンを起動できなくなります。
アプローチ別のメリットとデメリット
用途や目的に応じて、この問題へのアプローチは主に3つあります。
1. 完全ソフトウェアエミュレーション(QEMU TCG)
L1上で/dev/kvmを必要とせず、すべてのCPU命令をソフトウェアで処理します。
トレードオフ: ハードウェア仮想化と比較してパフォーマンスが80〜90%低下します。数十MB程度のAlpine Linuxのシェルを試す程度なら使えますが、KubernetesクラスタやCephを動かすのは到底不可能です。
2. 専用ベアメタルサーバークラスタの契約
HetznerやOVHなどのプロバイダーで、独立した物理サーバーを3台レンタルします。
トレードオフ: パフォーマンスは100%発揮され本番環境と同等になりますが、月額コストが150〜300ドル程度かかり、個人の検証用途としては高額すぎます。
3. KVM Nested VirtualizationとHost-Passthroughの有効化
物理CPUの命令セットをそのままL1仮想マシンへとパススルーするようにL0ホストを設定します。これはステージング環境、CI/CDパイプライン、DevOps/インフラエンジニアの検証ラボにおいて業界標準となっている構成です。物理マシンと比較したL2の性能オーバーヘッドは、通常わずか5%〜15%程度に抑えられます。
KVM Nested Virtualizationを有効化する手順
設定作業は、ハードウェアの確認、カーネルモジュールの有効化、VMのCPU設定、L1内部での検証という4つのステップで進めます。
ステップ1:L0ホストでハードウェア要件を確認
物理CPUが仮想化支援機能をサポートしているかを確認します。
egrep -c '(vmx|svm)' /proc/cpuinfo
返される数値はCPUのスレッド数に対応します(例:8、16、32など)。もし結果が「0」の場合は、マザーボードのBIOS/UEFI設定に入り、Intel VT-xまたはAMD-V(SVM Mode)を有効にする必要があります。
次に、ホスト上でネスト機能が有効になっているかステータスを確認します。
# Intel CPUの場合:
cat /sys/module/kvm_intel/parameters/nested
# AMD CPUの場合:
cat /sys/module/kvm_amd/parameters/nested
結果がNまたは0と表示された場合は無効になっています。Yまたは1が返された場合は、ステップ2をスキップしてステップ3に直接進んで構いません。
ステップ2:ホストカーネルでKVMモジュールを有効化
注意:モジュールを再ロードする前に、L0上で動作しているすべてのVMを停止してください。VMが起動したままだと、modprobe -rコマンド実行時にModule is in useエラーが発生します。
# Intel CPUの一時的な適用:
sudo modprobe -r kvm_intel
sudo modprobe kvm_intel nested=1
# AMD CPUの一時的な適用:
sudo modprobe -r kvm_amd
sudo modprobe kvm_amd nested=1
システムの再起動後も設定を永続化させるため、modprobe用の設定ファイルを作成します。
# Intel CPUの場合:
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm.conf
# AMD CPUの場合:
echo "options kvm_amd nested=1" | sudo tee /etc/modprobe.d/kvm.conf
再度/sys/module/kvm_intel/parameters/nested(またはkvm_amd)の内容を確認します。結果がYまたは1になっていれば設定完了です。
ステップ3:L1仮想マシン向けにCPUパススルーを設定
ホストカーネル側での準備が整ったので、次はL1仮想マシンが物理CPUを正しく認識できるように構成します。
virsh(libvirt)で管理しているVMの場合、XML設定ファイルを開きます。
virsh edit <L1-VM名>
<cpu>ブロックを探し、mode='host-passthrough'属性を指定します。
<cpu mode='host-passthrough' check='none'>
<topology sockets='1' dies='1' cores='4' threads='1'/>
</cpu>
GUIツールのvirt-managerを使用する場合の同等の操作手順:
- VMの詳細ウィンドウを開き、CPUs項目を選択します。
- Copy host CPU configurationにチェックを入れます(またはModel欄に
host-passthroughと入力)。 - Applyをクリックして設定を保存し、VMを起動します。
ステップ4:L1仮想マシンの内部から動作確認
L1仮想マシンを起動し、SSHでログインして以下のコマンドを実行します。
# 仮想化フラグが認識されているか確認
egrep -c '(vmx|svm)' /proc/cpuinfo
# KVMハードウェアアクセラレーションデバイスの存在を確認
ls -l /dev/kvm
カウント結果が0より大きい数値となり、キャラクターデバイス/dev/kvm(kvmグループのパーミッション)が存在していれば確認完了です。これでL1仮想マシンは物理サーバーと同等に振る舞う準備が整いました。
これで、Proxmox VEクラスタの展開や3ノード構成のHA設定、VMware ESXiの導入など、L2仮想マシンを快適に作成・運用できるようになります。複雑な検証ラボ環境も、1台のサーバー上にすっきりと集約できます。

