Skip to content
Published on

[仮想化] 02. QEMUとKVM: オープンソース仮想化の中核

Authors

はじめに

QEMU(Quick Emulator)はオープンソースのマシンエミュレータおよび仮想化ツールです。単独ではソフトウェアエミュレーションを、KVMと組み合わせるとハードウェアアクセラレーション仮想化を提供します。OpenStack、Proxmox、libvirtなど主要クラウドプラットフォームの中核エンジンです。

QEMUアーキテクチャ

システムエミュレーション vs ユーザーモードエミュレーション

QEMUは2つの実行モードを提供します。

[System Emulation]                    [User-mode Emulation]

+-------------------+                 +-------------------+
|    Guest OS       |                 |  Guest Binary     |
|  (Full System)    |                 |  (Single Process) |
+-------------------+                 +-------------------+
| Virtual Hardware  |                 | Syscall変換レイヤー|
| CPU, RAM, Disk,   |                 | (Linux-user /     |
| NIC, GPU, USB     |                 |  BSD-user)        |
+-------------------+                 +-------------------+
|    QEMU Engine    |                 |    QEMU Engine    |
+-------------------+                 +-------------------+
|   Host OS / HW    |                 |   Host OS / HW    |
+-------------------+                 +-------------------+

システムエミュレーション(qemu-system-*):

  • コンピュータシステム全体をエミュレーション
  • CPU、メモリ、ディスク、ネットワークなどすべてのハードウェアを仮想化
  • 異なるアーキテクチャのOSを実行可能(例:x86上でARM Linuxを実行)

ユーザーモードエミュレーション(qemu-*):

  • 単一バイナリのみエミュレーション
  • 異なるアーキテクチャ用プログラムを現在のシステムで実行
  • システムコールをホストOSのシステムコールに変換
# システムエミュレーション例: ARMシステムの起動
qemu-system-aarch64 \
  -M virt -cpu cortex-a72 \
  -m 2G -nographic \
  -kernel Image -append "console=ttyAMA0"

# ユーザーモードエミュレーション例: ARMバイナリをx86で実行
qemu-aarch64 ./arm-binary

TCG: Tiny Code Generator

KVMなしで動作する場合、QEMUはTCG(Tiny Code Generator)というJITコンパイラを使用します。

TCGの動作フロー

Guest Code (例: ARM)
    |
    v
[Frontend] ゲスト命令をデコード
    |
    v
TCG IR (Intermediate Representation)
    |
    v
[Backend] ホスト命令に変換 (例: x86)
    |
    v
Translation Block (TB) をキャッシュ
    |
    v
Host CPUで実行

Translation Block(TB):

  • ゲストコードの基本ブロック(分岐点まで)を単位として変換
  • 変換されたTBはキャッシュに保存して再利用
  • TBチェイニングで頻繁に実行されるパスを最適化
  • TCGは純粋なソフトウェア方式のためKVMより10〜100倍遅い
[TCG Translation Blockキャッシュ]

Guest PC 0x1000 --> TB #1 (Host code at 0x7f001000)
Guest PC 0x1040 --> TB #2 (Host code at 0x7f001200)
Guest PC 0x1080 --> TB #3 (Host code at 0x7f001400)
         ...
TB #1 --> TB #2 --> TB #3  (チェイニングで直接ジャンプ)

Block Layer: ストレージ管理

ディスクイメージフォーマット

フォーマット特徴用途
qcow2Copy-on-Write、スナップショット、圧縮、暗号化QEMUデフォルト、プロダクション
rawオーバーヘッドなし、最高のI/O性能パフォーマンス重視
vmdkVMware互換VMwareからの移行
vdiVirtualBox互換VirtualBoxからの移行
vpc/vhdxHyper-V互換Hyper-Vからの移行
# qcow2イメージの作成(シンプロビジョニング)
qemu-img create -f qcow2 disk.qcow2 100G

# スナップショットの作成
qemu-img snapshot -c snap1 disk.qcow2

# スナップショット一覧の確認
qemu-img snapshot -l disk.qcow2

# イメージフォーマットの変換
qemu-img convert -f vmdk -O qcow2 source.vmdk target.qcow2

# イメージ情報の確認
qemu-img info disk.qcow2

外部ストレージバックエンド

+------------------+
|     Guest VM     |
+------------------+
|  VirtIO-blk/SCSI |
+------------------+
|  QEMU Block Layer|
+--+--+--+--+--+--+
   |  |  |  |  |
   v  v  v  v  v
 File NBD iSCSI Ceph GlusterFS
              RBD
  • NBD(Network Block Device): リモートディスク共有
  • Ceph RBD: 分散ストレージベースのブロックデバイス
  • GlusterFS: 分散ファイルシステムベースのボリューム
  • iSCSI: IPネットワークベースのブロックストレージ

デバイスエミュレーションとVirtIO

エミュレーション vs 準仮想化

[従来のエミュレーション]             [VirtIO準仮想化]

Guest OS                            Guest OS
  |                                   |
  v                                   v
エミュレートされたe1000 NIC         VirtIO-netドライバ
  |                                   |
  v                                   v
QEMUが全レジスタ                  共有メモリリングバッファ
アクセスを処理(多数のVM Exit)     (最小限のVM Exit)
  |                                   |
  v                                   v
Host NIC                            Host NIC

VirtIOデバイスの種類:

VirtIOデバイス機能パフォーマンス向上
virtio-netネットワーク10倍以上(e1000比)
virtio-blkブロックストレージ2〜5倍(IDEエミュレーション比)
virtio-scsiSCSIストレージ多数のディスクに最適
virtio-gpuグラフィックス3Dアクセラレーション(virgl)
virtio-fsファイル共有ホスト-ゲストファイルシステム共有
virtio-balloonメモリ動的メモリ調整

ネットワークバックエンド

+--------+    +--------+    +--------+
| VM 1   |    | VM 2   |    | VM 3   |
| virtio |    | virtio |    | virtio |
+---+----+    +---+----+    +---+----+
    |             |             |
+---+-------------+-------------+---+
|          Linux Bridge              |
|          (virbr0)                  |
+----------------+-------------------+
                 |
            Physical NIC
              (eth0)
バックエンド説明ユースケース
SLIRP (user)ユーザーモードNAT、設定簡単開発/テスト
TAP/TUNカーネルレベル仮想NICプロダクション
BridgeTAPをブリッジに接続VM間通信、外部アクセス
macvtapmacvlan + TAP結合シンプルなL2接続
vhost-netカーネル内VirtIO処理高パフォーマンスネットワーキング
# TAP + Bridgeネットワーク設定
sudo ip link add br0 type bridge
sudo ip link set eth0 master br0
sudo ip link set br0 up

# QEMUでTAPネットワークを使用
qemu-system-x86_64 \
  -netdev tap,id=net0,ifname=tap0,script=no \
  -device virtio-net-pci,netdev=net0

KVM統合: ハードウェアアクセラレーション仮想化

KVM_RUN ioctlフロー

QEMU Process (User Space)
    |
    | ioctl(KVM_RUN)
    v
KVM Module (Kernel Space)
    |
    | VMLAUNCH / VMRESUME
    v
Guest Mode (VMX non-root)
    |
    | VM Exit発生
    v
KVM Module (Kernel Space)
    |
    | KVMが処理可能 -> 直接処理
    | 不可能 -> QEMUに返却
    v
QEMU Process (User Space)
    |
    | デバイスエミュレーション等を処理
    | 再度 ioctl(KVM_RUN)
    v
    ... (繰り返し)

KVMが処理するVM Exit:

  • ほとんどのMSRアクセス
  • 単純なI/Oポートアクセス
  • EPT違反(メモリマッピング)
  • 外部割り込み

QEMUに転送されるVM Exit:

  • 複雑なデバイスI/O
  • MMIO(Memory-Mapped I/O)アクセス
  • 一部のCPUIDリクエスト

QEMU + KVMパフォーマンス

[パフォーマンス比較 (相対値, ネイティブ = 100)]

CPU演算 (整数/浮動小数点):
  Native:    ████████████████████████████████████████ 100%
  QEMU+KVM:  ███████████████████████████████████████  98%
  QEMU(TCG): ██████████                               25%

ディスクI/O (VirtIO):
  Native:    ████████████████████████████████████████ 100%
  QEMU+KVM:  ████████████████████████████████████     90%
  QEMU(TCG): ████████████                             30%

ネットワーク (vhost-net):
  Native:    ████████████████████████████████████████ 100%
  QEMU+KVM:  ██████████████████████████████████████   95%
  QEMU(TCG): ██████████                               25%

GPUパススルー(VFIO)

GPUをVMに直接接続してネイティブに近いグラフィックス性能を提供します。

セットアップ手順

# 1. IOMMUの有効化(GRUBで)
# Intel: intel_iommu=on iommu=pt
# AMD: amd_iommu=on iommu=pt

# 2. IOMMUグループの確認
for d in /sys/kernel/iommu_groups/*/devices/*; do
  n=$(basename "$d")
  echo "IOMMU Group $(basename $(dirname $(dirname "$d"))): $n $(lspci -nns "$n")"
done

# 3. GPUをvfio-pciにバインド
# GPUのベンダー:デバイスIDを確認
lspci -nn | grep -i nvidia
# 出力例: 01:00.0 VGA ... [10de:2484]
# 出力例: 01:00.1 Audio ... [10de:228b]

# vfio-pciにバインド
echo "10de 2484" > /sys/bus/pci/drivers/vfio-pci/new_id
echo "10de 228b" > /sys/bus/pci/drivers/vfio-pci/new_id

# 4. QEMUでGPUパススルーを実行
qemu-system-x86_64 \
  -enable-kvm \
  -m 16G \
  -cpu host \
  -smp 8 \
  -device vfio-pci,host=01:00.0,multifunction=on \
  -device vfio-pci,host=01:00.1 \
  -drive if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd \
  -drive if=pflash,format=raw,file=OVMF_VARS.fd \
  -drive file=vm-disk.qcow2,format=qcow2,if=virtio

VFIOアーキテクチャ

+-------------------+
|    Guest VM       |
|  (GPUドライバ)    |
+-------------------+
|   VFIO-PCI        |
|  (パススルー層)   |
+-------------------+
|    IOMMU           |
|  (DMAリマッピング) |
+-------------------+
|  Physical GPU      |
|  (NVIDIA/AMD)     |
+-------------------+
  • IOMMUがDMAリクエストをリマッピングしてVM間のメモリ分離を保証
  • 同じIOMMUグループのすべてのデバイスを一緒にパススルーする必要がある
  • OVMF(UEFIファームウェア)でGPU BIOSを初期化
  • GPU1台は1つのVMにのみ独占割り当て

実践的なVM作成例

# 基本的なVMの作成と実行
qemu-system-x86_64 \
  -enable-kvm \
  -name "ubuntu-server" \
  -m 4G \
  -smp cores=4 \
  -cpu host \
  -drive file=ubuntu.qcow2,format=qcow2,if=virtio \
  -cdrom ubuntu-22.04-server.iso \
  -boot d \
  -device virtio-net-pci,netdev=net0 \
  -netdev user,id=net0,hostfwd=tcp::2222-:22 \
  -vnc :1 \
  -monitor stdio

# SSH接続(ホストから)
ssh -p 2222 user@localhost

# ライブマイグレーション(ソースから)
# 宛先ホストで同じVM設定に -incoming tcp:0:4444 オプションを追加して起動後
# ソースで実行(QEMUモニター):
# migrate tcp:dest-host:4444

ユースケース

ユースケース説明
OpenStackNova computeでlibvirt+QEMU/KVMをデフォルトハイパーバイザーとして使用
Proxmox VEWeb UIベースのKVM仮想化 + LXCコンテナ統合管理
開発環境クロスアーキテクチャ開発(x86上でARMなど)
セキュリティ研究マルウェア分析、脆弱性調査のための隔離環境
CI/CDクリーンなテスト環境を素早く作成/削除
組み込み開発QEMUで様々なボードをエミュレーション

クイズ: QEMU/KVM理解度チェック

Q1. QEMUのシステムエミュレーションとユーザーモードエミュレーションの違いは何ですか?

システムエミュレーションはコンピュータシステム全体(CPU、メモリ、ディスクなど)をエミュレートして完全なOSを実行します。ユーザーモードエミュレーションは単一バイナリのみをエミュレートし、システムコールをホストOSに変換します。

Q2. TCGがKVMより遅い理由は何ですか?

TCGはゲスト命令をIR(中間表現)に変換した後、ホスト命令に再変換するソフトウェアJITコンパイル方式です。KVMはハードウェア仮想化拡張(VT-x/AMD-V)を活用してゲストコードをCPUで直接実行するため、はるかに高速です。

Q3. VirtIOがエミュレートされたe1000 NICより速い理由は?

エミュレートされたe1000はすべてのレジスタアクセスでVM Exitが発生します。VirtIOは共有メモリリングバッファを使用して大量のデータを最小限のVM Exitで転送するため、オーバーヘッドが大幅に削減されます。

Q4. GPUパススルーでIOMMUグループが重要な理由は?

同じIOMMUグループのデバイスはDMAを通じて互いのメモリにアクセスできます。セキュリティのため、同じグループのすべてのデバイスを1つのVMに一緒に割り当てるか、すべて隔離する必要があります。

Q5. qcow2フォーマットの利点は何ですか?

Copy-on-Writeによるシンプロビジョニングをサポートし、スナップショット、圧縮、暗号化機能を内蔵しています。100GBのディスクを作成しても、実際に書き込まれたデータ分のみホストストレージを消費します。