虚拟化让一台物理机变成很多台机器。理解它,是理解云、容器、CI/CD 的前提。
硬件资源是独占的。虚拟化要把 CPU、内存、磁盘、网卡切分并隔离给多个"虚拟机"使用,且互相不可见、互不干扰。
| 类型 | 名字 | 架构 | 代表 |
|---|---|---|---|
| Type 1 | 裸金属 hypervisor | 直接跑在硬件上 | KVM、Xen、VMware ESXi、Hyper-V |
| Type 2 | 宿主式 hypervisor | 跑在操作系统上 | VirtualBox、VMware Workstation、QEMU(纯模拟) |
KVM 有点特殊:它是内核模块,把 Linux 内核本身变成 Type 1 hypervisor。所以严格说 Linux + KVM = Type 1。
flowchart TB
subgraph T1["KVM 架构(Type 1 性质)"]
HW1["硬件 CPU/内存/磁盘/网卡"] --> KVM1["Linux 内核 + KVM 模块"]
KVM1 --> VM1["VM1 (QEMU 进程)"]
KVM1 --> VM2["VM2 (QEMU 进程)"]
end
subgraph T2["VirtualBox 架构(Type 2)"]
HW2["硬件"] --> HOSTOS["宿主 OS"]
HOSTOS --> VB["VirtualBox"]
VB --> VM3["VM"]
end
四个组件,各司其职,新手最容易搞混:
| 组件 | 角色 | 说明 |
|---|---|---|
| KVM | 硬件加速 | 内核模块,利用 CPU 虚拟化扩展(Intel VT-x / AMD-V) |
| QEMU | 设备模拟 + 虚拟机进程 | 模拟主板、显卡、磁盘、网卡;每个 VM 就是一个 QEMU 进程 |
| libvirt | 统一管理层 | 提供 API、守护进程、配置文件格式 |
| virsh / virt-manager | 用户界面 | 命令行 / 图形界面 |
类比:KVM 是发动机,QEMU 是整车,libvirt 是方向盘,virsh 是仪表盘。
$ lsmod | grep kvm # kvm 与 kvm_intel/kvm_amd
$ lscpu | grep -i -E "vmx|svm" # CPU 是否支持虚拟化 ← 第一步确认
$ kvm-ok # 检查环境(需 cpu-checker)
$ ls /dev/kvm # 设备存在说明可用
$ systemctl status libvirtd
$ groups | grep libvirt # 用 virsh 需要加入 libvirt 组若 lscpu 里看不到 vmx/svm:需要在 BIOS 里启用虚拟化,或它已被别的 hypervisor 占用(嵌套虚拟化场景)。
QEMU 有两种模式,这个区分很重要:
| 模式 | 说明 | 性能 |
|---|---|---|
全系统模拟(qemu-system-x86_64) |
模拟整台机器,可跑不同架构 | 同架构时靠 KVM 加速;跨架构极慢 |
用户态模拟(qemu-x86_64 / qemu-aarch64) |
只模拟一个程序,跑在宿主内核上 | 适合测试交叉编译产物 |
# 用户态模拟:在本机跑 ARM64 程序
$ qemu-aarch64-static ./hello.arm64
# 注册 binfmt:让内核自动用 qemu 执行异构二进制
$ sudo apt install qemu-user-static binfmt-support
$ update-binfmts --display | grep qemu
# 命令行直接起一台虚拟机(不用 libvirt)
$ qemu-system-x86_64 \
-enable-kvm -cpu host -smp 4 -m 4096 \
-drive file=disk.qcow2,if=virtio \
-netdev user,id=n0 -device virtio-net-pci,netdev=n0 \
-nographic常用参数:
| 参数 | 含义 |
|---|---|
-enable-kvm |
启用硬件加速(不加会慢十倍) |
-cpu host |
透传宿主 CPU 特性(性能最好) |
-smp N |
vCPU 数量 |
-m 4096 |
内存 MB |
-drive if=virtio |
用 virtio 磁盘(必须用,性能差异巨大) |
-netdev user |
用户态网络(NAT,最简单) |
-nographic |
无图形,串口到终端 |
-snapshot |
不写回磁盘(测试用) |
| 格式 | 特点 |
|---|---|
raw |
裸格式,性能最好,不支持快照 |
qcow2 |
QEMU 原生,支持快照/压缩/加密/后备文件 |
vmdk / vdi / vhd |
各厂商格式 |
$ qemu-img create -f qcow2 disk.qcow2 20G # 创建(稀疏,不占满)
$ qemu-img info disk.qcow2
$ qemu-img convert -f qcow2 -O raw disk.qcow2 disk.raw
$ qemu-img resize disk.qcow2 +10G # 扩容(VM 内还要扩分区)
$ qemu-img snapshot -c snap1 disk.qcow2libvirt 把 QEMU/KVM、Xen、LXC 等统一成一套 API,并提供了实用的周边功能(网络、存储池、快照、迁移)。
$ virsh list --all # 所有虚机(含关机状态)
$ virsh dominfo vm1
$ virsh start vm1
$ virsh shutdown vm1 # 优雅关机(需 guest 装 agent)
$ virsh destroy vm1 # 强制断电(⚠️ 相当于拔电源)
$ virsh reboot vm1
$ virsh console vm1 # 连接串口控制台
$ virsh autostart vm1 # 开机自启
$ virsh edit vm1 # 编辑 XML 定义(改完需重启域生效)
$ virsh dumpxml vm1 > vm1.xml # 导出定义
$ virsh define vm1.xml # 从 XML 定义虚机
$ virsh undefine vm1 --remove-all-storage # 删除(⚠️ 不可逆)libvirt 的真相是 XML。理解结构就好办了:
<domain type='kvm'>
<name>vm1</name>
<memory unit='MiB'>4096</memory>
<vcpu>4</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='hd'/>
</os>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none' io='native'/>
<source file='/var/lib/libvirt/images/vm1.qcow2'/>
<target dev='vda' bus='virtio'/> <!-- virtio:性能关键 -->
</disk>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
</interface>
<graphics type='spice' port='-1' autoport='yes'/>
<channel type='unix'> <!-- guest agent 通道 -->
<target type='virtio' name='org.qemu.guest_agent.0'/>
</channel>
</devices>
</domain>$ virsh domblklist vm1 # 磁盘列表
$ virsh domiflist vm1 # 网卡列表
$ virsh domstats vm1 # 资源统计$ virsh pool-list --all
$ virsh pool-define-as mypool dir --target /data/vms
$ virsh pool-build mypool && virsh pool-start mypool && virsh pool-autostart mypool
$ virsh vol-list mypool
$ virsh vol-create-as mypool newdisk.qcow2 20G --format qcow2
$ virsh vol-info --pool mypool newdisk.qcow2libvirt 默认有一个 NAT 网络 default(virbr0,192.168.122.0/24):
$ virsh net-list --all
$ virsh net-dumpxml default
$ virsh net-edit default
$ virsh net-start default ; virsh net-autostart default
$ ip addr show virbr0| 模式 | 说明 | 用途 |
|---|---|---|
network(NAT) |
默认,虚机可出网,外部不能直接访问 | 桌面日常 |
bridge(桥接) |
虚机像物理机一样在同一网段 | 服务器 |
macvtap |
直连物理网卡 | 高性能,但宿主机与 VM 通信受限 |
hostdev(SR-IOV/VFIO) |
网卡直通 | 最高性能 |
桥接网络会占用宿主机的一个网络"位置",且无线网卡通常不支持桥接(这是笔记本上桥接失败的常见原因)。
$ sudo virt-install \
--name debian12 \
--vcpus 4 --memory 4096 \
--disk path=/var/lib/libvirt/images/debian12.qcow2,size=30,format=qcow2,bus=virtio \
--cdrom /data/iso/debian-12.iso \
--network network=default,model=virtio \
--graphics spice \
--os-variant debian12 \
--boot uefi \
--noautoconsole云镜像 + cloud-init 是现代做法:不用装系统,直接给它一份配置。
#cloud-config user-data
#cloud-config
hostname: web01
users:
- name: deploy
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy@laptop
package_update: true
packages: [nginx, htop]
runcmd:
- systemctl enable --now nginx$ sudo virt-install \
--name web01 --memory 2048 --vcpus 2 \
--disk /var/lib/libvirt/images/web01.qcow2,size=20,bus=virtio \
--import \
--cloud-init user-data=user-data.yaml,meta-data=meta-data.yaml \
--network network=default,model=virtio --noautoconsole$ virsh snapshot-list vm1
$ virsh snapshot-create-as vm1 pre-upgrade "升级前快照" --disk-only --atomic
$ virsh snapshot-revert vm1 pre-upgrade # ⚠️ 会丢弃之后的所有数据
$ virsh snapshot-delete vm1 pre-upgrade --metadata
$ virsh blockcommit vm1 vda --active --pivot # 合并回基础镜像
⚠️ 快照不是备份。它依赖原磁盘文件,原盘坏了快照一起完。快照链太长还会严重影响性能。正式备份用导出或存储层快照。
$ virsh domifaddr vm1 --source agent # 从 guest agent 拿 IP
$ virsh qemu-agent-command vm1 '{"execute":"guest-info"}'
$ ssh user@192.168.122.10 # 直接 SSH(NAT 网络)
$ virsh console vm1 # 串口控制台(虚拟内配置过 console 才行)
$ virsh attach-disk vm1 /data/extra.qcow2 vdb --driver qemu --subdriver qcow2 # 热插盘guest agent(qemu-guest-agent)很重要:没有它,virsh shutdown 会退化成断电,也拿不到 IP 等信息。
把物理 PCI 设备(显卡、网卡、NVMe)直接给虚机用,接近原生性能。
$ lspci -nn # 拿设备 ID
$ sudo dmesg | grep -i -E "DMAR|IOMMU" # 确认 IOMMU 开启
# 内核参数需加 intel_iommu=on iommu=pt(Intel)或 amd_iommu=on
$ ls /sys/kernel/iommu_groups/ # 设备能否分组独立
$ virsh nodedev-list --cap pci
$ virsh nodedev-dumpxml pci_0000_01_00_0关键约束:设备必须与宿主要使用的设备在同一个 IOMMU 组里才能安全直通(否则要 ACS 覆盖)。这是显卡直通的最大障碍。
# 绑定到 vfio-pci 驱动(要在宿主机驱动加载前)
$ echo "options vfio-pci ids=10de:2504,10de:228e" | sudo tee /etc/modprobe.d/vfio.conf
$ sudo update-initramfs -u把运行中的虚机从一台宿主机搬到另一台,几乎不停机。
$ virsh migrate --live --persistent --verbose vm1 \
qemu+ssh://host2/system --undefinesource
$ virsh migrate --live --copy-storage-all vm1 qemu+ssh://host2/system # 共享存储不可用时前提:两台宿主机 CPU 特性兼容、共享存储(或全量拷贝)、网络互通、libvirt 允许。
在虚机里再跑虚机(CI 环境、学 KVM 必需)。
$ cat /sys/module/kvm_intel/parameters/nested # Y 表示开启
$ echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm.conf
$ sudo modprobe -r kvm_intel && sudo modprobe kvm_intel
# 虚机 CPU 模式需设为 host-passthrough(否则 guest 看不到 vmx)| 层次 | 优化 | 效果 |
|---|---|---|
| CPU | -cpu host / host-passthrough |
大 |
| 磁盘 | virtio + cache=none + io=native |
很大 |
| 磁盘 | 存储用 LVM/裸设备而非 qcow2 文件 | 中 |
| 网络 | virtio + vhost-net | 大 |
| 网络 | SR-IOV / VFIO 直通 | 最大 |
| 内存 | 大页(hugepages) | 中 |
| 图形 | 别用图形,用 -nographic + 串口 |
大 |
$ sudo tuned-adm profile virtual-host # 系统级调优(RHEL 系)
$ virsh domstats vm1 --vcpu --interface --block| 症状 | 排查 |
|---|---|
| 虚机起不来 | virsh start vm1 报错 + /var/log/libvirt/qemu/vm1.log |
Could not access KVM kernel module |
BIOS 未开虚拟化 / /dev/kvm 权限 / 嵌套被禁 |
| 虚机极慢 | 忘了 --enable-kvm;没用 virtio 磁盘/网卡 |
| 网络不通 | virsh net-list 是否 active;guest 内 IP;virbr0 防火墙 |
| 磁盘满 | qemu-img info 看实际占用;qcow2 稀疏文件会增长 |
| 无法优雅关机 | 缺 qemu-guest-agent |
| 直通失败 | IOMMU 组冲突、vfio 绑定时机、内核参数 |
| 迁移失败 | CPU 特性不兼容、存储未共享、网络不通 |
$ virsh --debug 5 start vm1 2>&1 | tail -50
$ journalctl -u libvirtd -n 100
$ sudo cat /var/log/libvirt/qemu/vm1.log
$ virsh domstate vm1 --reason # 为什么是当前状态- KVM 不是虚拟机管理器,它只是内核加速模块,管理靠 libvirt。
- QEMU 不等于慢:配了 KVM 就是硬件加速的。
- 快照不是备份。
virsh destroy是强制断电,不是"删除虚机"(删除是undefine)。- 改了 XML 不会自动生效,要重启(或部分支持热插拔)。
- 无线网卡不能桥接。
- KVM 内部机制(VMCS、vCPU 调度、影子页表/EPT)
- virtio 协议与 vhost/vhost-user 加速原理
- GPU 直通完整实操(含 NVIDIA 驱动反检测)
- SR-IOV 网卡虚拟化
- Proxmox VE / oVirt / Incus 等平台
- Xen 架构与 dom0/domU
- 内存气球(ballooning)与 KSM 内存合并
- 虚机性能基准测试方法
- 与云厂商实例类型的对应关系(AWS EC2 / 阿里云 ECS)