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),让虚拟机指令不经模拟直接执行,性能接近物理机。

完整的虚拟化栈分为三层:

  1. KVM 内核模块(kvm.ko + kvm_intel/kvm_amd):提供 CPU 虚拟化和内存虚拟化,负责 VM 的创建、vcpu 调度、内存管理。仅暴露 /dev/kvm 字符设备给用户空间。
  2. QEMU(Quick Emulator):用户空间的设备模拟器,模拟 BIOS、磁盘、网卡、USB 等外设,每个 VM 对应一个 qemu-system-x86_64 进程。QEMU 通过 /dev/kvm 将 VM 指令交给 KVM 加速,自身只模拟非 CPU 设备。
  3. 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

磁盘格式深入对比

特性qcow2rawlvm
精简配置(按需占用)支持需 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 foundCPU 不支持虚拟化或 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 configurationCPU 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
快照生命周期管理快照链过长会拖慢写入并膨胀磁盘升级窗口期创建快照,确认稳定后立即删除;长期保留用完整备份

练习题

  1. 运行 grep -Ec '(vmx|svm)' /proc/cpuinfo 检查本机是否支持硬件虚拟化。如果不支持,记录报错信息并说明为什么需要在 BIOS 中开启 VT-x/AMD-V。
  2. 使用 virt-install 创建一个 1 vCPU / 1 GB 内存 / 10 GB 磁盘的 Ubuntu Server 虚拟机,网络使用默认 NAT。安装完成后用 virsh list --all 确认状态。
  3. 为已存在的虚拟机配置开机自启,然后用 virsh shutdown 关机,再重启宿主机后验证虚拟机是否自动启动。
  4. 在宿主机上创建一个 Linux 网桥 br0,将物理网卡 ens33 桥接到 br0。然后用 virt-install --network bridge=br0 创建一个新虚拟机,确认 VM 能从局域网 DHCP 获取独立 IP。
  5. 对比 KVM 虚拟机与 Docker 容器的隔离层级和适用场景。给出一个"必须用虚拟机、不能用容器"的真实案例,并解释原因。
点击查看答案
  1. 若输出为 0,说明 CPU 不支持 VT-x/AMD-V 或 BIOS 未开启。硬件虚拟化是 KVM 运行的基础,没有它 KVM 无法直接执行 VM 指令,QEMU 只能退回到纯软件模拟(极慢)。
  2. 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。
  3. virsh autostart ubuntu-vm 设置开机自启。关机后用 virsh start ubuntu-vm 启动。重启宿主机后 virsh list --all 应看到 VM 自动运行。
  4. netplan 配置 br0 桥接 ens33;virt-install --network bridge=br0 创建 VM;VM 内 ip addr 应看到 DHCP 分配的局域网 IP,能从局域网其他机器 ping 通。
  5. 必须用 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图形化管理工具远程管理 & 硬件添加

学习路径

  1. 掌握 virsh 基本操作(list/start/shutdown/destroy/autostart)
  2. 用 virt-install 创建至少一台虚拟机(交互式 + cloud-init 两种方式)
  3. 配置 bridge 网络,理解 NAT 与 bridge 的区别
  4. 学习 qemu-img 磁盘管理(创建、转换、resize、快照)
  5. 掌握 virsh dumpxml / define / edit 管理域 XML
  6. 进阶:OVS 虚拟交换机、PCI/USB 透传、NVIDIA vGPU、在线迁移

延伸阅读

常见问题

KVM 和 VirtualBox 性能差距大吗?
KVM(Kernel-based Virtual Machine)是内核级虚拟化,利用硬件辅助虚拟化(VT-x/AMD-V),性能接近原生。VirtualBox 在桌面使用更方便,但 I/O 性能不如 KVM。服务器场景必须用 KVM,桌面实验用 VirtualBox 或 VMware Workstation 即可。
虚拟机镜像太大怎么优化?
使用 cloud-init 基础镜像安装系统,避免装完再清理。在虚拟机关机后用 virt-sparsify 压缩空白空间。qcow2 格式比 raw 更小(支持 copy-on-write),配合 -o preallocation=metadata 只预分配元数据。不需要 GUI 的服务器用最小化安装。
什么时候用 KVM 什么时候用 Docker?
需要完整内核隔离、运行不同操作系统、或跑 Windows 程序时用 KVM(虚拟机)。应用隔离、快速部署、微服务场景用 Docker(容器)。实际生产经常两者组合:KVM 虚拟出多台宿主机,每台宿主机上跑 Docker 运行应用。
↑ 回到顶部