第 4 章 · 虚拟机管理

VM 造出来了,接下来是「养」:启动、关机、看状态、改配置、备份、删除。这一章的主角是 virsh,它是 libvirt 的命令行入口,也是云平台底层真正在调的东西。学完这章,「虚拟机的生命周期管理」这件事你就有了完整的工具箱;再配合克隆和快照,你会拥有物理机时代想都不敢想的灵活度。

4.1 libvirt:中间层为什么存在

VM 的实际执行者是 QEMU 进程,但没人直接手搓 qemu 命令行管 VM(参数几十个、状态难持久),中间隔了一个管理层 libvirt:守护进程 libvirtd 常驻,向上给 virsh/virt-manager/各语言 API 提供统一接口,向下适配 KVM、Xen、QEMU 等不同 Hypervisor。

virsh / virt-manager / 云平台 SDK
            │
       libvirtd(统一 API,VM 定义存 XML)
            │
       QEMU 进程(每台 VM 一个)── /dev/kvm

这个中间层的价值:VM 的配置以 XML 持久化(/etc/libvirt/qemu/demo.xml),virsh 命令改的就是它;所有工具(包括 OpenStack 这类云平台)说同一种「libvirt 方言」。学 virsh 不是学一个命令行工具,是在学虚拟化世界的「普通话」。

4.2 生命周期:从开机到注销

virsh list --all           # 所有 VM(含关机状态)
virsh start demo           # 开机
virsh reboot demo          # 重启
virsh shutdown demo        # 优雅关机:给 guest 的 ACPI 发关机信号,系统走正常流程
virsh destroy demo         # 强制断电:相当于拔电源线,guest 没有任何机会收尾!
virsh suspend demo         # 暂停(冻结所有 vCPU,内存还在)
virsh resume demo          # 恢复
virsh autostart demo       # 随 libvirtd 开机自启
virsh undefine demo --remove-all-storage   # 注销定义并删磁盘

shutdown 和 destroy 的区别值得单独强调,因为这是真实事故产地:shutdown 让 guest 内核走正常的 sync + unmount + poweroff(数据安全,但要几秒到几十秒);destroy 直接 SIGKILL 掉 QEMU 进程,guest 相当于断电,数据库这类应用断电即脏(第 8 章的崩溃恢复全靠日志兜底)。运维铁律:先 shutdown,超时再 destroy;写自动化脚本时永远给 shutdown 配一个等待循环。

virsh 还有个交互模式,直接 virsh 回车进入,Tab 补全体验不错,探索命令的好地方。

4.3 看状态:-dominfo、domstat 与 console

virsh dominfo demo         # 静态信息:UUID、内存、CPU 数、状态
virsh domstats demo        # 动态统计:CPU 用量、磁盘 IO、网络流量
virsh domifaddr demo       # 查 VM 的 IP 地址(常用!配合 ssh 直连)

virsh domifaddr demo 查到 IP 后,ssh user@IP 就能进去,比每次开控制台舒服得多。挂在控制台上看启动日志:virsh console demo(VM 装系统时配了 serial 的话,第 3 章的做法),Ctrl+] 退出。

4.4 克隆:造一台一模一样的

十台一样的测试机,手装十遍是噩梦。 virt-clone 复制现有 VM(磁盘整份拷贝 + 新名字 + 新 MAC):

virt-clone --original demo --name demo-clone --auto-clone
virsh start demo-clone

克隆出来的系统连主机名、IP 冲突、SSH host key 都是原样的,第一件事是登进去改 hostname 和 host key(rm /etc/machine-id; systemd-machine-id-setup; rm /etc/ssh/ssh_host_*; dpkg-reconfigure openssh-server)。更工程化的方案是模板 + cloud-init(装系统时就配好自动应答),属于进阶内容,知道方向即可。

4.5 快照:时光机

快照保存 VM 某一时刻的状态(磁盘 + 可选内存),之后随时跳回:

virsh snapshot-create-as demo clean-state      # 打快照
virsh snapshot-list demo
# 在 VM 里折腾(装错软件、删错文件……)
virsh snapshot-revert demo clean-state         # 一键回到过去
virsh snapshot-delete demo clean-state

原理(qcow2 的 COW 特性):打快照后原镜像不再写入,新写入进一个 overlay 文件,回滚 = 扔掉 overlay。所以快照不是备份(它依赖原镜像文件),宿主磁盘坏了照样全灭;快照管「回滚」,备份管「容灾」,两码事。实验机的正确姿势:装好基础环境打个 clean-state 快照,之后随便造,坏了秒回。

常见错误

  • destroy 当关机用。4.2 的重申:数据库 VM 被 destroy 后可能起不来(需要日志恢复),故障时间翻倍。
  • 克隆后 IP 冲突。两台 VM 一样的 IP,DHCP 分配乱套;克隆完第一件事改配置。
  • undefine 忘了 --remove-all-storage。VM 没了,几十 G 的磁盘文件还在镜像目录里吃灰,磁盘慢慢满。
  • 快照攒了一堆不打理。每个快照的 overlay 链越拉越长,IO 变慢;用完就删,或定期合并(blockcommit)。

练习

  1. 动手:把第 3 章的 VM 完整走一遍生命周期:start → domifaddr → ssh 进去 → shutdown → destroy(对比两种关机时 VM 内的体验:在 guest 里开着 syslog 观察)→ start → undefine --remove-all-storage,每步记录 virsh 输出。
  2. 动手:克隆一台 VM 并修复「身份问题」(hostname、machine-id、SSH host key),两台同时开机,验证 IP 已不同。
  3. 动手:快照实验:打快照 → 删一个系统文件制造损坏 → snapshot-revert 恢复 → 验证文件回来了;再 qemu-img info 看快照后的镜像文件结构(内部快照列表)。
  4. 思考:libvirt 把每台 VM 抽象成一份 XML。从「基础设施即代码」的角度,这份 XML 和 Docker 的 Dockerfile(第 12 章)、Kubernetes 的 YAML 是不是同一思想的不同实现?各自描述的对象有什么本质区别?