5.3 KVM 虚拟化技术入门
预计阅读时间:14 分钟
📖 目录
学习目标
- 理解 KVM/QEMU/libvirt 三层架构及各自职责
- 掌握 virsh 命令行管理虚拟机的生命周期(启动、关机、销毁、开机自启)
- 会用 virt-install 从 ISO 或 cloud-init 创建虚拟机
- 能配置 Linux 网桥(bridge),让虚拟机接入物理网络
- 区分 KVM 虚拟机与 Docker 容器的适用场景
核心知识
| 概念 | KVM 虚拟机 | Docker 容器 |
|---|---|---|
| 隔离层级 | 硬件级虚拟化,每个 VM 有独立内核 | 进程级隔离,共享宿主机内核 |
| 启动速度 | 数十秒到分钟级(完整引导) | 毫秒到秒级 |
| 资源开销 | 较高,每 VM 需分配专用内存/CPU | 极低,仅进程额外开销 |
| 适用场景 | 运行不同 OS、需要内核级隔离(如 Windows、安全合规) | 微服务、DevOps、CI/CD、同 OS 应用打包 |
| 镜像体积 | GB 级(完整 OS) | MB~百 MB 级 |
| 持久化 | 天然持久,磁盘文件即虚拟机 | 容器默认 ephemeral,需挂载卷 |
关联理解:容器解决了"环境一致性和快速部署",虚拟机解决了"完全隔离和异构 OS"。在生产中常组合使用——KVM 承载 Kubernetes 节点,节点内跑 Docker 容器。
知识关联
- 前置知识:5.5:防火墙实战 iptables/nftables 防火墙实战(Linux 网桥/iptables)、rhcsa01 磁盘分区与 LVM(磁盘分区与文件系统)、3.1:Docker 容器入门 Docker 容器入门(容器与虚拟机的对比参照)
- 后续影响:6.2:Kubernetes 入门 Kubernetes 入门(KVM 可作为 K8s 集群底层节点)、5.1:Linux 安全加固 Linux 安全加固(虚拟机隔离与安全合规)
- 配套技术:KVM + libvirt + QEMU 是 Linux 虚拟化标准栈,cloud-init 实现虚拟机初始化自动化,oVirt/Proxmox 提供 Web 管理面
原理讲解
KVM(Kernel-based Virtual Machine)是 Linux 内核模块,它将 Linux 转变为 Type-1 Hypervisor。KVM 模块直接利用 CPU 硬件虚拟化扩展(Intel VT-x / AMD-V),让虚拟机指令不经模拟直接执行,性能接近物理机。
完整的虚拟化栈分为三层:
- KVM 内核模块(kvm.ko + kvm_intel/kvm_amd):提供 CPU 虚拟化和内存虚拟化,负责 VM 的创建、vcpu 调度、内存管理。仅暴露
/dev/kvm字符设备给用户空间。 - QEMU(Quick Emulator):用户空间的设备模拟器,模拟 BIOS、磁盘、网卡、USB 等外设,每个 VM 对应一个
qemu-system-x86_64进程。QEMU 通过/dev/kvm将 VM 指令交给 KVM 加速,自身只模拟非 CPU 设备。 - libvirt:虚拟化管理守护进程(
libvirtd),提供统一 API 和命令行工具virsh。libvirt 管理 QEMU 进程生命周期、网络、存储池,并支持安全认证(SELinux / AppArmor)。
网络方面,默认的 NAT 模式(virbr0)让 VM 通过宿主机 IP 访问外网,宿主机外无法直连 VM。Bridge 模式将 VM 网卡直接桥接到物理网卡,VM 获取局域网独立 IP,可被外网直接访问。
内存虚拟化与超分配
KVM 使用 EPT(Intel)或 NPT(AMD)硬件页表扩展完成客户机内存地址转换,虚拟机访问内存几乎无额外开销。宿主机默认按虚拟机配置的 <memory> 大小预留物理内存,但 KVM 支持内存超分配(overcommit):配合 virtio-balloon 驱动,客户机空闲内存可以被 balloon 回收给宿主机,其他 VM 再按需使用。
超分配是把双刃剑:过度分配会导致宿主机 swap 抖动(thrashing),整机性能崩塌。经验规则:物理内存 64GB 的宿主机,分配总量控制在 70-80%(约 45-50GB),且优先保证数据库类 VM 不被超配。查看实际占用:virsh dommemstat vm1 --live 观察 unused 值,判断 balloon 回收了多少。
CPU 模型与迁移兼容性
虚拟机看到的 CPU 特性由 QEMU 的 CPU model 决定。host-passthrough 直接把宿主机 CPU 全部特性透传给 VM,性能最高,但两台不同型号 CPU 的宿主机之间无法做在线迁移。生产推荐 host-model:QEMU 自动选择与宿主机兼容且可迁移的型号集合。混用新旧 CPU 的集群,可指定 qemu64/Skylake-Client 等固定模型换取迁移兼容性。
# 查看当前 CPU model
virsh dumpxml vm1 | grep -i cpu
# 输出: <cpu mode='host-model' check='partial'/>
# 在线热插 vCPU(客户机内核需支持)
virsh setvcpus vm1 4 --live --config
磁盘格式深入对比
| 特性 | qcow2 | raw | lvm |
|---|---|---|---|
| 精简配置(按需占用) | 支持 | 需 fallocate 手动预留 | 支持 |
| 快照 | 内建快照 | 不支持(需外部快照) | LVM 快照 |
| 压缩/加密 | 支持 | 不支持 | 依赖文件系统/设备 |
| 读写性能 | 略低(元数据开销) | 最优 | 接近 raw |
| 典型场景 | 日常通用 | 数据库、高 IO 业务 | 需要精简+快照的数据库 |
qcow2 的性能差异主要来自写时分配,可通过 qemu-img convert 在业务低峰把冷数据卷转成 raw 提升 IO,或为 qcow2 开启 preallocation=full 消除运行时分配开销。
示例代码
1. 环境准备与安装
# 检查 CPU 是否支持虚拟化
grep -Ec '(vmx|svm)' /proc/cpuinfo # 输出: 4(注意:egrep 已废弃,推荐用 grep -E)
# Ubuntu / Debian
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients \
virtinst virt-manager bridge-utils
# CentOS / RHEL
# sudo dnf install -y qemu-kvm libvirt virt-install virt-manager bridge-utils
# 将当前用户加入 libvirt 组(免 sudo 运行 virsh)
sudo usermod -aG libvirt $USER
newgrp libvirt # 或重新登录
# 验证安装
virsh list --all # 输出: Id Name State
ls /dev/kvm
systemctl status libvirtd # 输出: ● libvirtd.service - Virtualization daemon
2. virsh 生命周期管理
# 列出所有虚拟机(含未启动)
virsh list --all # 输出: Id Name State
# 启动 / 正常关机 / 强制断电
virsh start ubuntu-vm # 输出: Domain ubuntu-vm started
virsh shutdown ubuntu-vm # 输出: Domain ubuntu-vm is being shutdown
virsh destroy ubuntu-vm # 输出: Domain ubuntu-vm destroyed
# 设置开机自启
virsh autostart ubuntu-vm # 输出: Domain ubuntu-vm marked as autostarted
virsh autostart --disable ubuntu-vm # 输出: Domain ubuntu-vm unmarked as autostarted
# 定义虚拟机(从 XML 定义文件)
virsh define /path/to/vm.xml # 输出: Domain ubuntu-vm defined from /path/to/vm.xml
# 导出/导入配置
virsh dumpxml ubuntu-vm > ubuntu-vm.xml
virsh create ubuntu-vm.xml # 输出: Domain ubuntu-vm created from ubuntu-vm.xml
# 暂停/恢复
virsh suspend ubuntu-vm # 输出: Domain ubuntu-vm suspended
virsh resume ubuntu-vm # 输出: Domain ubuntu-vm resumed
3. virt-install 创建虚拟机
# 从 ISO 交互安装
sudo virt-install \
--name ubuntu-vm \
--ram 2048 \
--vcpus 2 \
--disk size=20,path=/var/lib/libvirt/images/ubuntu-vm.qcow2 \
--cdrom /tmp/ubuntu-24.04-server.iso \
--network network=default \
--graphics vnc,listen=0.0.0.0 \
--os-variant ubuntu24.04
# 从 cloud-init 无人值守创建(先准备 seed.img)
# 创建 cloud-init ISO:
# cat > meta-data <<EOF
# instance-id: ubuntu-vm; local-hostname: ubuntu-vm
# EOF
# cat > user-data <<EOF
# #cloud-config
# password: passw0rd
# chpasswd: { expire: False }
# ssh_pwauth: True
# EOF
# sudo mkisofs -o /var/lib/libvirt/images/seed.iso -V cidata -J -r meta-data user-data
sudo virt-install \
--name ubuntu-vm \
--ram 2048 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/ubuntu-vm.qcow2,size=20 \
--disk path=/var/lib/libvirt/images/seed.iso,device=cdrom \
--network network=default \
--os-variant ubuntu24.04 \
--graphics none \
--console pty,target_type=serial
4. 桥接网络配置
# 创建网桥 br0(Ubuntu netplan 示例)
# /etc/netplan/01-bridge.yaml:
network:
version: 2
ethernets:
enp3s0:
dhcp4: no
bridges:
br0:
interfaces: [enp3s0]
dhcp4: yes
# 应用 netplan
sudo netplan apply
# 或使用 nmcli(NetworkManager 环境)
# sudo nmcli connection add type bridge ifname br0
# sudo nmcli connection add type ethernet slave-type bridge \
# con-name bridge-port-enp3s0 ifname enp3s0 master br0
# sudo nmcli connection up br0
# 创建使用桥接的虚拟机
sudo virt-install \
--name br-vm \
--ram 2048 \
--vcpus 2 \
--disk size=20 \
--network bridge=br0 \
--cdrom ubuntu.iso \
--os-variant ubuntu24.04
# 查看网桥信息
brctl show # 输出: bridge name bridge id STP enabled interfaces
bridge link show
5. virt-manager 图形化使用
# 启动 virt-manager(需图形环境)
virt-manager
# 常用操作:创建 VM → 导入或新建存储卷 → 添加硬件(网卡/磁盘/USB 透传)
# 连接远程主机:File → Add Connection → QEMU/KVM + ssh 远程地址
6. qemu-img 磁盘管理
# 创建磁盘(精简配置)
qemu-img create -f qcow2 vm1.qcow2 50G
# 查看磁盘真实占用
qemu-img info vm1.qcow2
# 输出: virtual size: 50 GiB ... disk size: 8.2 GiB
# 格式转换(qcow2 → raw,性能优化)
qemu-img convert -O raw vm1.qcow2 vm1.raw
# 扩容磁盘(先扩磁盘,再进客户机扩分区)
qemu-img resize vm1.qcow2 80G
# 开启写时预分配,避免首次写入卡顿
qemu-img create -f qcow2 -o preallocation=full vm2.qcow2 20G
# 压缩镜像(回收空闲空间,注意需先停机)
qemu-img convert -O qcow2 -c vm1.qcow2 vm1-compact.qcow2
7. 快照与回滚
# 在线快照(qcow2 内建,不停机)
virsh snapshot-create-as vm1 pre-upgrade \
--description "升级前快照" --atomic
# 列出快照
virsh snapshot-list vm1
# 输出: Name Creation Time State
# pre-upgrade 2026-07-28 10:00:00 running
# 查看快照磁盘占用
virsh snapshot-info vm1 pre-upgrade
# 回滚到快照(先关机,回滚后快照链保留)
virsh shutdown vm1
virsh snapshot-revert vm1 pre-upgrade --paused
virsh resume vm1
# 删除快照(合并数据到基础镜像)
virsh snapshot-delete vm1 pre-upgrade
# 磁盘级快照(不经 libvirt,需停机)
qemu-img snapshot -c pre_upgrade vm1.qcow2
qemu-img snapshot -l vm1.qcow2
8. 虚拟机迁移
# 冷迁移(停机迁移):导出 XML + 拷贝磁盘
virsh dumpxml vm1 > vm1.xml
virsh shutdown vm1
scp vm1.qcow2 node2:/var/lib/libvirt/images/
scp vm1.xml node2:/tmp/
# 在目标节点定义并启动
virsh define /tmp/vm1.xml
virsh start vm1
# 在线迁移(需共享存储 NFS/iSCSI,磁盘免拷贝)
virsh migrate --live vm1 qemu+ssh://root@node2/system
# 迁移前检查目标节点可迁移性
virsh migrate --live vm1 qemu+ssh://root@node2/system --dry-run
# 迁移时带宽限制(MB/s),避免挤占业务流量
virsh migrate --live --bandwidth 200 vm1 qemu+ssh://root@node2/system
# 查看迁移状态
virsh domjobinfo vm1
常见错误
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
/dev/kvm not found | CPU 不支持虚拟化或 BIOS 中 VT-x/AMD-V 未开启 | 进入 BIOS 开启虚拟化;云服务器选支持嵌套虚拟化的实例类型 |
libvirtd 未运行 | libvirt 服务未启动或未启用开机自启 | sudo systemctl enable --now libvirtd |
permission denied / cannot access /dev/kvm | 当前用户不在 kvm/libvirt 组 | sudo usermod -aG kvm,libvirt $USER 后重新登录 |
Network not found: network 'default' | 默认 NAT 网络未定义或未激活 | sudo virsh net-start default; sudo virsh net-autostart default |
| 虚拟机启动后无法获取 IP | 虚拟机内未启用 DHCP 或网卡驱动不兼容 | 检查 VM 网卡模型(推荐 virtio),或改用 e1000 |
| 虚拟机卡顿/负载高,宿主机却空闲 | CPU 被限制为固定型号(如 qemu64),或 balloon 驱动未安装 | 改用 host-model,客户机安装 virtio/spice-guest-tools 完整驱动 |
在线迁移失败:unsupported configuration | CPU model 不一致或设备(磁盘/网卡)未共享 | 两端统一 host-model,磁盘放共享存储,--dry-run 先演练 |
| 快照回滚后数据丢失 | 回滚只恢复到快照时刻的数据,期间写入全部丢弃 | 回滚前确认业务已停,快照策略与备份策略结合使用 |
| qemu-img resize 后客户机看不到新空间 | 磁盘扩容后还需要在客户机内扩分区和文件系统 | growpart /dev/vda 1 + resize2fs /dev/vda1(或 xfs_growfs) |
最佳实践
| 实践 | 说明 | 推荐做法 |
|---|---|---|
| 磁盘格式选择 | qcow2 支持精简配置、快照、压缩;raw 性能最优但无高级特性 | 日常用 qcow2;高性能场景(数据库)用 raw 或直通 LVM |
| CPU 与内存分配 | vCPU 总数不应超过物理 CPU 线程数,避免 CPU 过载竞争 | 预留宿主机 1-2 核 + 1-2 GB 内存;使用 virsh vcpupin 绑定物理 CPU |
| 网络模型 | NAT 适合测试环境,Bridge 适合生产需要直连的场景 | 生产环境一律用 bridge 模式;安全域隔离用 OVS(Open vSwitch) |
| 存储后端 | 本地存储简单但缺高可用;NFS/iSCSI 支持在线迁移 | 单机用 qcow2 本地存储;集群用共享存储(NFS/GlusterFS/Ceph) |
| 备份策略 | 虚拟机备份包括:域 XML + 磁盘文件 + 网络配置 | 定期 virsh dumpxml 导出配置;qcow2 用 virsh snapshot-create-as 做快照 |
| 安全加固 | 默认 SELinux 为 VM 进程提供隔离,不要轻易关闭 | 保持 SELinux enforcing;libvirt 使用 sVirt 标签为 VM 进程附加安全上下文 |
| CPU model 统一 | 不同 CPU 型号影响在线迁移的可行性 | 集群内统一 host-model,或按最老 CPU 指定固定模型 |
| 磁盘 IO 预留 | 多台 VM 抢写同一物理盘会导致 IO 抖动 | qemu-img 使用 preallocation=full;高 IO 业务独立 SSD 或走 LVM |
| 快照生命周期管理 | 快照链过长会拖慢写入并膨胀磁盘 | 升级窗口期创建快照,确认稳定后立即删除;长期保留用完整备份 |
练习题
- 运行
grep -Ec '(vmx|svm)' /proc/cpuinfo检查本机是否支持硬件虚拟化。如果不支持,记录报错信息并说明为什么需要在 BIOS 中开启 VT-x/AMD-V。 - 使用
virt-install创建一个 1 vCPU / 1 GB 内存 / 10 GB 磁盘的 Ubuntu Server 虚拟机,网络使用默认 NAT。安装完成后用virsh list --all确认状态。 - 为已存在的虚拟机配置开机自启,然后用
virsh shutdown关机,再重启宿主机后验证虚拟机是否自动启动。 - 在宿主机上创建一个 Linux 网桥
br0,将物理网卡 ens33 桥接到br0。然后用virt-install --network bridge=br0创建一个新虚拟机,确认 VM 能从局域网 DHCP 获取独立 IP。 - 对比 KVM 虚拟机与 Docker 容器的隔离层级和适用场景。给出一个"必须用虚拟机、不能用容器"的真实案例,并解释原因。
点击查看答案
- 若输出为 0,说明 CPU 不支持 VT-x/AMD-V 或 BIOS 未开启。硬件虚拟化是 KVM 运行的基础,没有它 KVM 无法直接执行 VM 指令,QEMU 只能退回到纯软件模拟(极慢)。
sudo virt-install --name ubuntu-vm --ram 1024 --vcpus 1 --disk size=10 --cdrom /path/to/ubuntu.iso --network network=default --os-variant ubuntu24.04。安装后用virsh list --all看到ubuntu-vm状态为 running 或 shut off。virsh autostart ubuntu-vm设置开机自启。关机后用virsh start ubuntu-vm启动。重启宿主机后virsh list --all应看到 VM 自动运行。- netplan 配置 br0 桥接 ens33;
virt-install --network bridge=br0创建 VM;VM 内ip addr应看到 DHCP 分配的局域网 IP,能从局域网其他机器 ping 通。 - 必须用 VM 的场景示例:需要运行 Windows 软件(如 .NET Framework 遗留应用)、需要独立内核定制(如加载特定内核模块)、安全合规要求硬件级隔离(如金融系统不同租户)。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 KVM/QEMU/libvirt 三层架构及各自职责 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 virsh 管理虚拟机生命周期、virt-install 创建虚拟机 | 在终端实际执行 |
| 原理掌握 | 能说出 KVM 虚拟机与 Docker 容器在隔离层级和适用场景上的区别 | 画出流程图 |
| 故障排查 | 能独立排查 /dev/kvm not found、虚拟机无法获取 IP 等问题 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么生产环境推荐使用 Bridge 网络而非 NAT | 对比不同方案 |
本章总结
速查表
| 命令 / 操作 | 用途 | 示例 |
|---|---|---|
virsh list --all | 列出所有虚拟机 | 查看已定义 VM 状态 |
virsh start/shutdown/destroy | 生命周期控制 | virsh start vm1 |
virsh autostart | 设置开机自启 | virsh autostart vm1 |
virt-install | 从命令行创建 VM | 参数覆盖:name/ram/vcpus/disk/network |
qemu-img create -f qcow2 | 创建虚拟磁盘 | qemu-img create -f qcow2 disk.qcow2 20G |
virsh dumpxml | 导出 VM 配置 XML | 备份 / 迁移时使用 |
brctl show | 查看网桥状态 | 确认 bridge 模式网络连通性 |
virsh snapshot-create-as | 创建磁盘快照 | 升级前快照便于回滚 |
virt-manager | 图形化管理工具 | 远程管理 & 硬件添加 |
学习路径
- 掌握 virsh 基本操作(list/start/shutdown/destroy/autostart)
- 用 virt-install 创建至少一台虚拟机(交互式 + cloud-init 两种方式)
- 配置 bridge 网络,理解 NAT 与 bridge 的区别
- 学习 qemu-img 磁盘管理(创建、转换、resize、快照)
- 掌握 virsh dumpxml / define / edit 管理域 XML
- 进阶:OVS 虚拟交换机、PCI/USB 透传、NVIDIA vGPU、在线迁移
延伸阅读
- libvirt 官方文档 — 最权威的 API 参考和 XML 配置手册
- QEMU 文档 — 设备模拟、命令行选项详解
- Arch Wiki KVM 页 — 社区维护的详尽 KVM 指南
- RHEL 虚拟化配置与管理 — Red Hat 官方虚拟化手册
- 容器底层原理 — 理解容器与虚拟机底层差异的姊妹篇