Skip to content

Latest commit

 

History

History
375 lines (298 loc) · 13.4 KB

12-virtualization.md

File metadata and controls

375 lines (298 loc) · 13.4 KB

12. 虚拟化

虚拟化让一台物理机变成很多台机器。理解它,是理解云、容器、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
Loading

二、核心组件(KVM 技术栈)

四个组件,各司其职,新手最容易搞混:

组件 角色 说明
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 有两种模式,这个区分很重要:

模式 说明 性能
全系统模拟(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.qcow2

四、libvirt:统一管理

libvirt 把 QEMU/KVM、Xen、LXC 等统一成一套 API,并提供了实用的周边功能(网络、存储池、快照、迁移)。

4.1 virsh 常用命令

$ 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  # 删除(⚠️ 不可逆)

4.2 XML 定义:虚拟机的"配置文件"

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                     # 资源统计

4.3 存储池

$ 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.qcow2

4.4 网络

libvirt 默认有一个 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) 网卡直通 最高性能

桥接网络会占用宿主机的一个网络"位置",且无线网卡通常不支持桥接(这是笔记本上桥接失败的常见原因)。

五、实战操作

5.1 用 virt-install 创建虚机

$ 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

5.2 cloud-init:无人值守初始化

云镜像 + 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

5.3 快照

$ 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  # 合并回基础镜像

⚠️ 快照不是备份。它依赖原磁盘文件,原盘坏了快照一起完。快照链太长还会严重影响性能。正式备份用导出或存储层快照。

5.4 虚拟机与宿主机的通信

$ 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 等信息。

六、进阶主题

6.1 设备直通(VFIO / IOMMU)

把物理 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

6.2 迁移(Live Migration)

把运行中的虚机从一台宿主机搬到另一台,几乎不停机。

$ virsh migrate --live --persistent --verbose vm1 \
    qemu+ssh://host2/system --undefinesource
$ virsh migrate --live --copy-storage-all vm1 qemu+ssh://host2/system   # 共享存储不可用时

前提:两台宿主机 CPU 特性兼容、共享存储(或全量拷贝)、网络互通、libvirt 允许。

6.3 嵌套虚拟化

在虚机里再跑虚机(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)

6.4 性能优化要点

层次 优化 效果
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)

← 上一章:运行时与开发工具链 · 返回目录 · 下一章:容器 →